#
tokens: 26023/50000 6/67 files (page 2/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 2. Use http://codebase.md/cyanheads/filesystem-mcp-server?page={x} to view the full context.

# Directory Structure

```
├── .clinerules
├── .dockerignore
├── .github
│   └── workflows
│       └── publish.yml
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── docs
│   └── tree.md
├── LICENSE
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── repomix.config.json
├── scripts
│   ├── clean.ts
│   └── tree.ts
├── smithery.yaml
├── src
│   ├── config
│   │   └── index.ts
│   ├── index.ts
│   ├── mcp-server
│   │   ├── server.ts
│   │   ├── state.ts
│   │   ├── tools
│   │   │   ├── copyPath
│   │   │   │   ├── copyPathLogic.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── registration.ts
│   │   │   ├── createDirectory
│   │   │   │   ├── createDirectoryLogic.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── registration.ts
│   │   │   ├── deleteDirectory
│   │   │   │   ├── deleteDirectoryLogic.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── registration.ts
│   │   │   ├── deleteFile
│   │   │   │   ├── deleteFileLogic.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── registration.ts
│   │   │   ├── listFiles
│   │   │   │   ├── index.ts
│   │   │   │   ├── listFilesLogic.ts
│   │   │   │   └── registration.ts
│   │   │   ├── movePath
│   │   │   │   ├── index.ts
│   │   │   │   ├── movePathLogic.ts
│   │   │   │   └── registration.ts
│   │   │   ├── readFile
│   │   │   │   ├── index.ts
│   │   │   │   ├── readFileLogic.ts
│   │   │   │   └── registration.ts
│   │   │   ├── setFilesystemDefault
│   │   │   │   ├── index.ts
│   │   │   │   ├── registration.ts
│   │   │   │   └── setFilesystemDefaultLogic.ts
│   │   │   ├── updateFile
│   │   │   │   ├── index.ts
│   │   │   │   ├── registration.ts
│   │   │   │   └── updateFileLogic.ts
│   │   │   └── writeFile
│   │   │       ├── index.ts
│   │   │       ├── registration.ts
│   │   │       └── writeFileLogic.ts
│   │   └── transports
│   │       ├── authentication
│   │       │   └── authMiddleware.ts
│   │       ├── httpTransport.ts
│   │       └── stdioTransport.ts
│   ├── types-global
│   │   ├── errors.ts
│   │   ├── mcp.ts
│   │   └── tool.ts
│   └── utils
│       ├── index.ts
│       ├── internal
│       │   ├── errorHandler.ts
│       │   ├── index.ts
│       │   ├── logger.ts
│       │   └── requestContext.ts
│       ├── metrics
│       │   ├── index.ts
│       │   └── tokenCounter.ts
│       ├── parsing
│       │   ├── dateParser.ts
│       │   ├── index.ts
│       │   └── jsonParser.ts
│       └── security
│           ├── idGenerator.ts
│           ├── index.ts
│           ├── rateLimiter.ts
│           └── sanitization.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Loads, validates, and exports application configuration.
 * This module centralizes configuration management, sourcing values from
 * environment variables and `package.json`. It uses Zod for schema validation
 * to ensure type safety and correctness of configuration parameters.
 *
 * Key responsibilities:
 * - Load environment variables from a `.env` file.
 * - Read `package.json` for default server name and version.
 * - Define a Zod schema for all expected environment variables.
 * - Validate environment variables against the schema.
 * - Construct and export a comprehensive `config` object.
 * - Export individual configuration values like `logLevel` and `environment` for convenience.
 *
 * @module src/config/index
 */

import dotenv from "dotenv";
import { existsSync, mkdirSync, readFileSync, statSync } from "fs";
import path, { dirname, join } from "path";
import { fileURLToPath } from "url";
import { z } from "zod";

dotenv.config();

// --- Determine Project Root ---
/**
 * Finds the project root directory by searching upwards for package.json.
 * @param startDir The directory to start searching from.
 * @returns The absolute path to the project root, or throws an error if not found.
 */
const findProjectRoot = (startDir: string): string => {
  let currentDir = startDir;
  while (true) {
    const packageJsonPath = join(currentDir, "package.json");
    if (existsSync(packageJsonPath)) {
      return currentDir;
    }
    const parentDir = dirname(currentDir);
    if (parentDir === currentDir) {
      // Reached the root of the filesystem without finding package.json
      throw new Error(
        `Could not find project root (package.json) starting from ${startDir}`,
      );
    }
    currentDir = parentDir;
  }
};

let projectRoot: string;
try {
  // For ESM, __dirname is not available directly.
  // import.meta.url gives the URL of the current module.
  const currentModuleDir = dirname(fileURLToPath(import.meta.url));
  projectRoot = findProjectRoot(currentModuleDir);
} catch (error: any) {
  console.error(`FATAL: Error determining project root: ${error.message}`);
  // Fallback to process.cwd() if project root cannot be determined.
  // This might happen in unusual execution environments.
  projectRoot = process.cwd();
  console.warn(
    `Warning: Using process.cwd() (${projectRoot}) as fallback project root.`,
  );
}
// --- End Determine Project Root ---

const pkgPath = join(projectRoot, "package.json"); // Use determined projectRoot
let pkg = { name: "mcp-ts-template", version: "0.0.0" };

try {
  pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
} catch (error) {
  if (process.stdout.isTTY) {
    console.error(
      "Warning: Could not read package.json for default config values. Using hardcoded defaults.",
      error,
    );
  }
}

/**
 * Zod schema for validating environment variables.
 * Provides type safety, validation, defaults, and clear error messages.
 * @private
 */
const EnvSchema = z.object({
  /** Optional. The desired name for the MCP server. Defaults to `package.json` name. */
  MCP_SERVER_NAME: z.string().optional(),
  /** Optional. The version of the MCP server. Defaults to `package.json` version. */
  MCP_SERVER_VERSION: z.string().optional(),
  /** Minimum logging level. See `McpLogLevel` in logger utility. Default: "debug". */
  MCP_LOG_LEVEL: z.string().default("debug"),
  /** Directory for log files. Defaults to "logs" in project root. */
  LOGS_DIR: z.string().default(path.join(projectRoot, "logs")),
  /** Runtime environment (e.g., "development", "production"). Default: "development". */
  NODE_ENV: z.string().default("development"),
  /** MCP communication transport ("stdio" or "http"). Default: "stdio". */
  MCP_TRANSPORT_TYPE: z.enum(["stdio", "http"]).default("stdio"),
  /** HTTP server port (if MCP_TRANSPORT_TYPE is "http"). Default: 3010. */
  MCP_HTTP_PORT: z.coerce.number().int().positive().default(3010),
  /** HTTP server host (if MCP_TRANSPORT_TYPE is "http"). Default: "127.0.0.1". */
  MCP_HTTP_HOST: z.string().default("127.0.0.1"),
  /** Optional. Comma-separated allowed origins for CORS (HTTP transport). */
  MCP_ALLOWED_ORIGINS: z.string().optional(),
  /** Optional. Secret key (min 32 chars) for auth tokens (HTTP transport). CRITICAL for production. */
  MCP_AUTH_SECRET_KEY: z
    .string()
    .min(
      32,
      "MCP_AUTH_SECRET_KEY must be at least 32 characters long for security reasons.",
    )
    .optional(),

  /** Optional. Application URL for OpenRouter integration. */
  OPENROUTER_APP_URL: z
    .string()
    .url("OPENROUTER_APP_URL must be a valid URL (e.g., http://localhost:3000)")
    .optional(),
  /** Optional. Application name for OpenRouter. Defaults to MCP_SERVER_NAME or package name. */
  OPENROUTER_APP_NAME: z.string().optional(),
  /** Optional. API key for OpenRouter services. */
  OPENROUTER_API_KEY: z.string().optional(),
  /** Default LLM model. Default: "google/gemini-2.5-flash-preview:thinking". */
  LLM_DEFAULT_MODEL: z
    .string()
    .default("google/gemini-2.5-flash-preview-05-20"),
  /** Optional. Default LLM temperature (0.0-2.0). */
  LLM_DEFAULT_TEMPERATURE: z.coerce.number().min(0).max(2).optional(),
  /** Optional. Default LLM top_p (0.0-1.0). */
  LLM_DEFAULT_TOP_P: z.coerce.number().min(0).max(1).optional(),
  /** Optional. Default LLM max tokens (positive integer). */
  LLM_DEFAULT_MAX_TOKENS: z.coerce.number().int().positive().optional(),
  /** Optional. Default LLM top_k (non-negative integer). */
  LLM_DEFAULT_TOP_K: z.coerce.number().int().nonnegative().optional(),
  /** Optional. Default LLM min_p (0.0-1.0). */
  LLM_DEFAULT_MIN_P: z.coerce.number().min(0).max(1).optional(),
  /** Optional. API key for Google Gemini services. */
  GEMINI_API_KEY: z.string().optional(),

  /** Optional. OAuth provider authorization endpoint URL. */
  OAUTH_PROXY_AUTHORIZATION_URL: z
    .string()
    .url("OAUTH_PROXY_AUTHORIZATION_URL must be a valid URL.")
    .optional(),
  /** Optional. OAuth provider token endpoint URL. */
  OAUTH_PROXY_TOKEN_URL: z
    .string()
    .url("OAUTH_PROXY_TOKEN_URL must be a valid URL.")
    .optional(),
  /** Optional. OAuth provider revocation endpoint URL. */
  OAUTH_PROXY_REVOCATION_URL: z
    .string()
    .url("OAUTH_PROXY_REVOCATION_URL must be a valid URL.")
    .optional(),
  /** Optional. OAuth provider issuer URL. */
  OAUTH_PROXY_ISSUER_URL: z
    .string()
    .url("OAUTH_PROXY_ISSUER_URL must be a valid URL.")
    .optional(),
  /** Optional. OAuth service documentation URL. */
  OAUTH_PROXY_SERVICE_DOCUMENTATION_URL: z
    .string()
    .url("OAUTH_PROXY_SERVICE_DOCUMENTATION_URL must be a valid URL.")
    .optional(),
  /** Optional. Comma-separated default OAuth client redirect URIs. */
  OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS: z.string().optional(),
  /** Optional. Base directory for all filesystem operations. If set, tools cannot access paths outside this directory. Can be an absolute path or relative to the project root. */
  FS_BASE_DIRECTORY: z.string().optional(),
});

const parsedEnv = EnvSchema.safeParse(process.env);

if (!parsedEnv.success) {
  if (process.stdout.isTTY) {
    console.error(
      "❌ Invalid environment variables found:",
      parsedEnv.error.flatten().fieldErrors,
    );
  }
  // Consider throwing an error in production for critical misconfigurations.
}

let env = parsedEnv.success ? parsedEnv.data : EnvSchema.parse({});

// Resolve FS_BASE_DIRECTORY if it's relative
let resolvedFsBaseDirectory: string | undefined = env.FS_BASE_DIRECTORY;
if (env.FS_BASE_DIRECTORY && !path.isAbsolute(env.FS_BASE_DIRECTORY)) {
  resolvedFsBaseDirectory = path.resolve(projectRoot, env.FS_BASE_DIRECTORY);
  if (process.stdout.isTTY) {
    console.log(
      `Info: Relative FS_BASE_DIRECTORY "${env.FS_BASE_DIRECTORY}" resolved to "${resolvedFsBaseDirectory}".`
    );
  }
}

if (process.stdout.isTTY) {
  if (resolvedFsBaseDirectory) {
    // Ensure the resolved directory exists, or attempt to create it.
    // This is a good place to also check if it's a directory.
    try {
      if (!existsSync(resolvedFsBaseDirectory)) {
        mkdirSync(resolvedFsBaseDirectory, { recursive: true });
        console.log(`Info: Created FS_BASE_DIRECTORY at "${resolvedFsBaseDirectory}".`);
      } else {
        const stats = statSync(resolvedFsBaseDirectory);
        if (!stats.isDirectory()) {
          console.error(`Error: FS_BASE_DIRECTORY "${resolvedFsBaseDirectory}" exists but is not a directory. Restriction will not be applied.`);
          resolvedFsBaseDirectory = undefined; // Disable restriction if path is invalid
        }
      }
      if (resolvedFsBaseDirectory) {
         console.log(
          `Info: Filesystem operations will be restricted to base directory: ${resolvedFsBaseDirectory}`
        );
      }
    } catch (error: any) {
      console.error(`Error processing FS_BASE_DIRECTORY "${resolvedFsBaseDirectory}": ${error.message}. Restriction will not be applied.`);
      resolvedFsBaseDirectory = undefined; // Disable restriction on error
    }
  } else {
    console.warn(
      "Warning: FS_BASE_DIRECTORY is not set. Filesystem operations will not be restricted to a base directory. This is a potential security risk."
    );
  }
}


// --- Directory Ensurance Function ---
/**
 * Ensures a directory exists and is within the project root.
 * @param dirPath The desired path for the directory (can be relative or absolute).
 * @param rootDir The root directory of the project to contain the directory.
 * @param dirName The name of the directory type for logging (e.g., "logs").
 * @returns The validated, absolute path to the directory, or null if invalid.
 */
const ensureDirectory = (
  dirPath: string,
  rootDir: string,
  dirName: string,
): string | null => {
  const resolvedDirPath = path.isAbsolute(dirPath)
    ? dirPath
    : path.resolve(rootDir, dirPath);

  // Ensure the resolved path is within the project root boundary
  if (
    !resolvedDirPath.startsWith(rootDir + path.sep) &&
    resolvedDirPath !== rootDir
  ) {
    if (process.stdout.isTTY) {
      console.error(
        `Error: ${dirName} path "${dirPath}" resolves to "${resolvedDirPath}", which is outside the project boundary "${rootDir}".`,
      );
    }
    return null;
  }

  if (!existsSync(resolvedDirPath)) {
    try {
      mkdirSync(resolvedDirPath, { recursive: true });
      if (process.stdout.isTTY) {
        console.log(`Created ${dirName} directory: ${resolvedDirPath}`);
      }
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : String(err);
      if (process.stdout.isTTY) {
        console.error(
          `Error creating ${dirName} directory at ${resolvedDirPath}: ${errorMessage}`,
        );
      }
      return null;
    }
  } else {
    try {
      const stats = statSync(resolvedDirPath);
      if (!stats.isDirectory()) {
        if (process.stdout.isTTY) {
          console.error(
            `Error: ${dirName} path ${resolvedDirPath} exists but is not a directory.`,
          );
        }
        return null;
      }
    } catch (statError: any) {
      if (process.stdout.isTTY) {
        console.error(
          `Error accessing ${dirName} path ${resolvedDirPath}: ${statError.message}`,
        );
      }
      return null;
    }
  }
  return resolvedDirPath;
};
// --- End Directory Ensurance Function ---

// --- Logs Directory Handling ---
const validatedLogsPath = ensureDirectory(env.LOGS_DIR, projectRoot, "logs");

if (!validatedLogsPath) {
  if (process.stdout.isTTY) {
    console.error(
      "FATAL: Logs directory configuration is invalid or could not be created. Please check permissions and path. Exiting.",
    );
  }
  process.exit(1); // Exit if logs directory is not usable
}
// --- End Logs Directory Handling ---

/**
 * Main application configuration object.
 * Aggregates settings from validated environment variables and `package.json`.
 */
export const config = {
  /** MCP server name. Env `MCP_SERVER_NAME` > `package.json` name > "mcp-ts-template". */
  mcpServerName: env.MCP_SERVER_NAME || pkg.name,
  /** MCP server version. Env `MCP_SERVER_VERSION` > `package.json` version > "0.0.0". */
  mcpServerVersion: env.MCP_SERVER_VERSION || pkg.version,
  /** Logging level. From `MCP_LOG_LEVEL` env var. Default: "debug". */
  logLevel: env.MCP_LOG_LEVEL,
  /** Absolute path to the logs directory. From `LOGS_DIR` env var. */
  logsPath: validatedLogsPath,
  /** Runtime environment. From `NODE_ENV` env var. Default: "development". */
  environment: env.NODE_ENV,
  /** MCP transport type ('stdio' or 'http'). From `MCP_TRANSPORT_TYPE` env var. Default: "stdio". */
  mcpTransportType: env.MCP_TRANSPORT_TYPE,
  /** HTTP server port (if http transport). From `MCP_HTTP_PORT` env var. Default: 3010. */
  mcpHttpPort: env.MCP_HTTP_PORT,
  /** HTTP server host (if http transport). From `MCP_HTTP_HOST` env var. Default: "127.0.0.1". */
  mcpHttpHost: env.MCP_HTTP_HOST,
  /** Array of allowed CORS origins (http transport). From `MCP_ALLOWED_ORIGINS` (comma-separated). */
  mcpAllowedOrigins: env.MCP_ALLOWED_ORIGINS?.split(",")
    .map((origin) => origin.trim())
    .filter(Boolean),
  /** Auth secret key (JWTs, http transport). From `MCP_AUTH_SECRET_KEY`. CRITICAL. */
  mcpAuthSecretKey: env.MCP_AUTH_SECRET_KEY,

  /** OpenRouter App URL. From `OPENROUTER_APP_URL`. Default: "http://localhost:3000". */
  openrouterAppUrl: env.OPENROUTER_APP_URL || "http://localhost:3000",
  /** OpenRouter App Name. From `OPENROUTER_APP_NAME`. Defaults to `mcpServerName`. */
  openrouterAppName: env.OPENROUTER_APP_NAME || pkg.name || "MCP TS App",
  /** OpenRouter API Key. From `OPENROUTER_API_KEY`. */
  openrouterApiKey: env.OPENROUTER_API_KEY,
  /** Default LLM model. From `LLM_DEFAULT_MODEL`. */
  llmDefaultModel: env.LLM_DEFAULT_MODEL,
  /** Default LLM temperature. From `LLM_DEFAULT_TEMPERATURE`. */
  llmDefaultTemperature: env.LLM_DEFAULT_TEMPERATURE,
  /** Default LLM top_p. From `LLM_DEFAULT_TOP_P`. */
  llmDefaultTopP: env.LLM_DEFAULT_TOP_P,
  /** Default LLM max tokens. From `LLM_DEFAULT_MAX_TOKENS`. */
  llmDefaultMaxTokens: env.LLM_DEFAULT_MAX_TOKENS,
  /** Default LLM top_k. From `LLM_DEFAULT_TOP_K`. */
  llmDefaultTopK: env.LLM_DEFAULT_TOP_K,
  /** Default LLM min_p. From `LLM_DEFAULT_MIN_P`. */
  llmDefaultMinP: env.LLM_DEFAULT_MIN_P,
  /** Gemini API Key. From `GEMINI_API_KEY`. */
  geminiApiKey: env.GEMINI_API_KEY,

  /** OAuth Proxy configurations. Undefined if no related env vars are set. */
  oauthProxy:
    env.OAUTH_PROXY_AUTHORIZATION_URL ||
    env.OAUTH_PROXY_TOKEN_URL ||
    env.OAUTH_PROXY_REVOCATION_URL ||
    env.OAUTH_PROXY_ISSUER_URL ||
    env.OAUTH_PROXY_SERVICE_DOCUMENTATION_URL ||
    env.OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS
      ? {
          authorizationUrl: env.OAUTH_PROXY_AUTHORIZATION_URL,
          tokenUrl: env.OAUTH_PROXY_TOKEN_URL,
          revocationUrl: env.OAUTH_PROXY_REVOCATION_URL,
          issuerUrl: env.OAUTH_PROXY_ISSUER_URL,
          serviceDocumentationUrl: env.OAUTH_PROXY_SERVICE_DOCUMENTATION_URL,
          defaultClientRedirectUris:
            env.OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS?.split(",")
              .map((uri) => uri.trim())
              .filter(Boolean),
        }
      : undefined,
  /** Base directory for filesystem operations. From `FS_BASE_DIRECTORY`. If set, operations are restricted to this path. Will be an absolute path. */
  fsBaseDirectory: resolvedFsBaseDirectory,
};

/**
 * Configured logging level for the application.
 * Exported for convenience.
 */
export const logLevel: string = config.logLevel;

/**
 * Configured runtime environment ("development", "production", etc.).
 * Exported for convenience.
 */
export const environment: string = config.environment;

```

--------------------------------------------------------------------------------
/src/utils/internal/errorHandler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview This module provides utilities for robust error handling.
 * It defines structures for error context, options for handling errors,
 * and mappings for classifying errors. The main `ErrorHandler` class
 * offers static methods for consistent error processing, logging, and transformation.
 * @module src/utils/internal/errorHandler
 */
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
import { generateUUID, sanitizeInputForLogging } from "../index.js";
import { logger } from "./logger.js";
import { RequestContext } from "./requestContext.js";

/**
 * Defines a generic structure for providing context with errors.
 * This context can include identifiers like `requestId` or any other relevant
 * key-value pairs that aid in debugging or understanding the error's circumstances.
 */
export interface ErrorContext {
  /**
   * A unique identifier for the request or operation during which the error occurred.
   * Useful for tracing errors through logs and distributed systems.
   */
  requestId?: string;

  /**
   * Allows for arbitrary additional context information.
   * Keys are strings, and values can be of any type.
   */
  [key: string]: unknown;
}

/**
 * Configuration options for the `ErrorHandler.handleError` method.
 * These options control how an error is processed, logged, and whether it's rethrown.
 */
export interface ErrorHandlerOptions {
  /**
   * The context of the operation that caused the error.
   * This can include `requestId` and other relevant debugging information.
   */
  context?: ErrorContext;

  /**
   * A descriptive name of the operation being performed when the error occurred.
   * This helps in identifying the source or nature of the error in logs.
   * Example: "UserLogin", "ProcessPayment", "FetchUserProfile".
   */
  operation: string;

  /**
   * The input data or parameters that were being processed when the error occurred.
   * This input will be sanitized before logging to prevent sensitive data exposure.
   */
  input?: unknown;

  /**
   * If true, the (potentially transformed) error will be rethrown after handling.
   * Defaults to `false`.
   */
  rethrow?: boolean;

  /**
   * A specific `BaseErrorCode` to assign to the error, overriding any
   * automatically determined error code.
   */
  errorCode?: BaseErrorCode;

  /**
   * A custom function to map or transform the original error into a new `Error` instance.
   * If provided, this function is used instead of the default `McpError` creation.
   * @param error - The original error that occurred.
   * @returns The transformed error.
   */
  errorMapper?: (error: unknown) => Error;

  /**
   * If true, stack traces will be included in the logs.
   * Defaults to `true`.
   */
  includeStack?: boolean;

  /**
   * If true, indicates that the error is critical and might require immediate attention
   * or could lead to system instability. This is primarily for logging and alerting.
   * Defaults to `false`.
   */
  critical?: boolean;
}

/**
 * Defines a basic rule for mapping errors based on patterns.
 * Used internally by `COMMON_ERROR_PATTERNS` and as a base for `ErrorMapping`.
 */
export interface BaseErrorMapping {
  /**
   * A string or regular expression to match against the error message.
   * If a string is provided, it's typically used for substring matching (case-insensitive).
   */
  pattern: string | RegExp;

  /**
   * The `BaseErrorCode` to assign if the pattern matches.
   */
  errorCode: BaseErrorCode;

  /**
   * An optional custom message template for the mapped error.
   * (Note: This property is defined but not directly used by `ErrorHandler.determineErrorCode`
   * which focuses on `errorCode`. It's more relevant for custom mapping logic.)
   */
  messageTemplate?: string;
}

/**
 * Extends `BaseErrorMapping` to include a factory function for creating
 * specific error instances and additional context for the mapping.
 * Used by `ErrorHandler.mapError`.
 * @template T The type of `Error` this mapping will produce, defaults to `Error`.
 */
export interface ErrorMapping<T extends Error = Error>
  extends BaseErrorMapping {
  /**
   * A factory function that creates and returns an instance of the mapped error type `T`.
   * @param error - The original error that occurred.
   * @param context - Optional additional context provided in the mapping rule.
   * @returns The newly created error instance.
   */
  factory: (error: unknown, context?: Record<string, unknown>) => T;

  /**
   * Additional static context to be merged or passed to the `factory` function
   * when this mapping rule is applied.
   */
  additionalContext?: Record<string, unknown>;
}

/**
 * Maps standard JavaScript error constructor names to `BaseErrorCode` values.
 * @private
 */
const ERROR_TYPE_MAPPINGS: Readonly<Record<string, BaseErrorCode>> = {
  SyntaxError: BaseErrorCode.VALIDATION_ERROR,
  TypeError: BaseErrorCode.VALIDATION_ERROR,
  ReferenceError: BaseErrorCode.INTERNAL_ERROR,
  RangeError: BaseErrorCode.VALIDATION_ERROR,
  URIError: BaseErrorCode.VALIDATION_ERROR,
  EvalError: BaseErrorCode.INTERNAL_ERROR,
};

/**
 * Array of `BaseErrorMapping` rules to classify errors by message/name patterns.
 * Order matters: more specific patterns should precede generic ones.
 * @private
 */
const COMMON_ERROR_PATTERNS: ReadonlyArray<Readonly<BaseErrorMapping>> = [
  {
    pattern:
      /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i,
    errorCode: BaseErrorCode.UNAUTHORIZED,
  },
  {
    pattern: /permission|forbidden|access.*denied|not.*allowed/i,
    errorCode: BaseErrorCode.FORBIDDEN,
  },
  {
    pattern: /not found|missing|no such|doesn't exist|couldn't find/i,
    errorCode: BaseErrorCode.NOT_FOUND,
  },
  {
    pattern:
      /invalid|validation|malformed|bad request|wrong format|missing required/i,
    errorCode: BaseErrorCode.VALIDATION_ERROR,
  },
  {
    pattern: /conflict|already exists|duplicate|unique constraint/i,
    errorCode: BaseErrorCode.CONFLICT,
  },
  {
    pattern: /rate limit|too many requests|throttled/i,
    errorCode: BaseErrorCode.RATE_LIMITED,
  },
  {
    pattern: /timeout|timed out|deadline exceeded/i,
    errorCode: BaseErrorCode.TIMEOUT,
  },
  {
    pattern: /service unavailable|bad gateway|gateway timeout|upstream error/i,
    errorCode: BaseErrorCode.SERVICE_UNAVAILABLE,
  },
];

/**
 * Creates a "safe" RegExp for testing error messages.
 * Ensures case-insensitivity and removes the global flag.
 * @param pattern - The string or RegExp pattern.
 * @returns A new RegExp instance.
 * @private
 */
function createSafeRegex(pattern: string | RegExp): RegExp {
  if (pattern instanceof RegExp) {
    let flags = pattern.flags.replace("g", "");
    if (!flags.includes("i")) {
      flags += "i";
    }
    return new RegExp(pattern.source, flags);
  }
  return new RegExp(pattern, "i");
}

/**
 * Retrieves a descriptive name for an error object or value.
 * @param error - The error object or value.
 * @returns A string representing the error's name or type.
 * @private
 */
function getErrorName(error: unknown): string {
  if (error instanceof Error) {
    return error.name || "Error";
  }
  if (error === null) {
    return "NullValueEncountered";
  }
  if (error === undefined) {
    return "UndefinedValueEncountered";
  }
  if (
    typeof error === "object" &&
    error !== null &&
    error.constructor &&
    typeof error.constructor.name === "string" &&
    error.constructor.name !== "Object"
  ) {
    return `${error.constructor.name}Encountered`;
  }
  return `${typeof error}Encountered`;
}

/**
 * Extracts a message string from an error object or value.
 * @param error - The error object or value.
 * @returns The error message string.
 * @private
 */
function getErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    return error.message;
  }
  if (error === null) {
    return "Null value encountered as error";
  }
  if (error === undefined) {
    return "Undefined value encountered as error";
  }
  if (typeof error === "string") {
    return error;
  }
  try {
    const str = String(error);
    if (str === "[object Object]" && error !== null) {
      try {
        return `Non-Error object encountered: ${JSON.stringify(error)}`;
      } catch (stringifyError) {
        return `Unstringifyable non-Error object encountered (constructor: ${error.constructor?.name || "Unknown"})`;
      }
    }
    return str;
  } catch (e) {
    return `Error converting error to string: ${e instanceof Error ? e.message : "Unknown conversion error"}`;
  }
}

/**
 * A utility class providing static methods for comprehensive error handling.
 */
export class ErrorHandler {
  /**
   * Determines an appropriate `BaseErrorCode` for a given error.
   * Checks `McpError` instances, `ERROR_TYPE_MAPPINGS`, and `COMMON_ERROR_PATTERNS`.
   * Defaults to `BaseErrorCode.INTERNAL_ERROR`.
   * @param error - The error instance or value to classify.
   * @returns The determined error code.
   */
  public static determineErrorCode(error: unknown): BaseErrorCode {
    if (error instanceof McpError) {
      return error.code;
    }

    const errorName = getErrorName(error);
    const errorMessage = getErrorMessage(error);

    if (errorName in ERROR_TYPE_MAPPINGS) {
      return ERROR_TYPE_MAPPINGS[errorName as keyof typeof ERROR_TYPE_MAPPINGS];
    }

    for (const mapping of COMMON_ERROR_PATTERNS) {
      const regex = createSafeRegex(mapping.pattern);
      if (regex.test(errorMessage) || regex.test(errorName)) {
        return mapping.errorCode;
      }
    }
    return BaseErrorCode.INTERNAL_ERROR;
  }

  /**
   * Handles an error with consistent logging and optional transformation.
   * Sanitizes input, determines error code, logs details, and can rethrow.
   * @param error - The error instance or value that occurred.
   * @param options - Configuration for handling the error.
   * @returns The handled (and potentially transformed) error instance.
   */
  public static handleError(
    error: unknown,
    options: ErrorHandlerOptions,
  ): Error {
    const {
      context = {},
      operation,
      input,
      rethrow = false,
      errorCode: explicitErrorCode,
      includeStack = true,
      critical = false,
      errorMapper,
    } = options;

    const sanitizedInput =
      input !== undefined ? sanitizeInputForLogging(input) : undefined;
    const originalErrorName = getErrorName(error);
    const originalErrorMessage = getErrorMessage(error);
    const originalStack = error instanceof Error ? error.stack : undefined;

    let finalError: Error;
    let loggedErrorCode: BaseErrorCode;

    const errorDetailsSeed =
      error instanceof McpError &&
      typeof error.details === "object" &&
      error.details !== null
        ? { ...error.details }
        : {};

    const consolidatedDetails: Record<string, unknown> = {
      ...errorDetailsSeed,
      ...context,
      originalErrorName,
      originalMessage: originalErrorMessage,
    };
    if (
      originalStack &&
      !(error instanceof McpError && error.details?.originalStack)
    ) {
      consolidatedDetails.originalStack = originalStack;
    }

    if (error instanceof McpError) {
      loggedErrorCode = error.code;
      finalError = errorMapper
        ? errorMapper(error)
        : new McpError(error.code, error.message, consolidatedDetails);
    } else {
      loggedErrorCode =
        explicitErrorCode || ErrorHandler.determineErrorCode(error);
      const message = `Error in ${operation}: ${originalErrorMessage}`;
      finalError = errorMapper
        ? errorMapper(error)
        : new McpError(loggedErrorCode, message, consolidatedDetails);
    }

    if (
      finalError !== error &&
      error instanceof Error &&
      finalError instanceof Error &&
      !finalError.stack &&
      error.stack
    ) {
      finalError.stack = error.stack;
    }

    const logRequestId =
      typeof context.requestId === "string" && context.requestId
        ? context.requestId
        : generateUUID();

    const logTimestamp =
      typeof context.timestamp === "string" && context.timestamp
        ? context.timestamp
        : new Date().toISOString();

    const logPayload: Record<string, unknown> = {
      requestId: logRequestId,
      timestamp: logTimestamp,
      operation,
      input: sanitizedInput,
      critical,
      errorCode: loggedErrorCode,
      originalErrorType: originalErrorName,
      finalErrorType: getErrorName(finalError),
      ...Object.fromEntries(
        Object.entries(context).filter(
          ([key]) => key !== "requestId" && key !== "timestamp",
        ),
      ),
    };

    if (finalError instanceof McpError && finalError.details) {
      logPayload.errorDetails = finalError.details;
    } else {
      logPayload.errorDetails = consolidatedDetails;
    }

    if (includeStack) {
      const stack =
        finalError instanceof Error ? finalError.stack : originalStack;
      if (stack) {
        logPayload.stack = stack;
      }
    }

    logger.error(
      `Error in ${operation}: ${finalError.message || originalErrorMessage}`,
      logPayload as unknown as RequestContext, // Cast to RequestContext for logger compatibility
    );

    if (rethrow) {
      throw finalError;
    }
    return finalError;
  }

  /**
   * Maps an error to a specific error type `T` based on `ErrorMapping` rules.
   * Returns original/default error if no mapping matches.
   * @template T The target error type, extending `Error`.
   * @param error - The error instance or value to map.
   * @param mappings - An array of mapping rules to apply.
   * @param defaultFactory - Optional factory for a default error if no mapping matches.
   * @returns The mapped error of type `T`, or the original/defaulted error.
   */
  public static mapError<T extends Error>(
    error: unknown,
    mappings: ReadonlyArray<ErrorMapping<T>>,
    defaultFactory?: (error: unknown, context?: Record<string, unknown>) => T,
  ): T | Error {
    const errorMessage = getErrorMessage(error);
    const errorName = getErrorName(error);

    for (const mapping of mappings) {
      const regex = createSafeRegex(mapping.pattern);
      if (regex.test(errorMessage) || regex.test(errorName)) {
        return mapping.factory(error, mapping.additionalContext);
      }
    }

    if (defaultFactory) {
      return defaultFactory(error);
    }
    return error instanceof Error ? error : new Error(String(error));
  }

  /**
   * Formats an error into a consistent object structure for API responses or structured logging.
   * @param error - The error instance or value to format.
   * @returns A structured representation of the error.
   */
  public static formatError(error: unknown): Record<string, unknown> {
    if (error instanceof McpError) {
      return {
        code: error.code,
        message: error.message,
        details:
          typeof error.details === "object" && error.details !== null
            ? error.details
            : {},
      };
    }

    if (error instanceof Error) {
      return {
        code: ErrorHandler.determineErrorCode(error),
        message: error.message,
        details: { errorType: error.name || "Error" },
      };
    }

    return {
      code: BaseErrorCode.UNKNOWN_ERROR,
      message: getErrorMessage(error),
      details: { errorType: getErrorName(error) },
    };
  }

  /**
   * Safely executes a function (sync or async) and handles errors using `ErrorHandler.handleError`.
   * The error is always rethrown.
   * @template T The expected return type of the function `fn`.
   * @param fn - The function to execute.
   * @param options - Error handling options (excluding `rethrow`).
   * @returns A promise resolving with the result of `fn` if successful.
   * @throws {McpError | Error} The error processed by `ErrorHandler.handleError`.
   * @example
   * ```typescript
   * async function fetchData(userId: string, context: RequestContext) {
   *   return ErrorHandler.tryCatch(
   *     async () => {
   *       const response = await fetch(`/api/users/${userId}`);
   *       if (!response.ok) throw new Error(`Failed to fetch user: ${response.status}`);
   *       return response.json();
   *     },
   *     { operation: 'fetchUserData', context, input: { userId } }
   *   );
   * }
   * ```
   */
  public static async tryCatch<T>(
    fn: () => Promise<T> | T,
    options: Omit<ErrorHandlerOptions, "rethrow">,
  ): Promise<T> {
    try {
      return await Promise.resolve(fn());
    } catch (error) {
      // ErrorHandler.handleError will return the error to be thrown.
      throw ErrorHandler.handleError(error, { ...options, rethrow: true });
    }
  }
}

```

--------------------------------------------------------------------------------
/scripts/tree.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

/**
 * Directory Tree Generation Operation
 * ==================================
 * 
 * A utility for generating visual tree representations of the project's directory
 * structure with configurable depth control and gitignore integration.
 *
 * This operation creates a formatted markdown file containing a hierarchical
 * representation of directories and files, respecting ignore patterns and
 * applying configurable filtering.
 * 
 * Features:
 * - Respects .gitignore patterns and common exclusions
 * - Configurable maximum depth traversal
 * - Customizable output location
 * - Sorting with directories first
 * - Cross-platform compatibility
 * 
 * @module utilities/generate.directory.tree.operation
 * 
 * Usage examples:
 * - Add to package.json: "tree": "ts-node scripts/tree.ts"
 * - Run directly: npm run tree
 * - Custom output: ts-node scripts/tree.ts ./documentation/structure.md
 * - Limit depth: ts-node scripts/tree.ts --depth=3
 * - Show help: ts-node scripts/tree.ts --help
 */

import fs from 'fs/promises';
import path from 'path';

// -----------------------------------
// Type Definitions
// -----------------------------------

/**
 * Standardized error category classification (using type alias instead of enum)
 */
type ErrorCategoryType = 
  | 'VALIDATION'
  | 'FILESYSTEM'
  | 'SYSTEM'
  | 'UNKNOWN';

const ErrorCategory = {
  VALIDATION: 'VALIDATION' as ErrorCategoryType,
  FILESYSTEM: 'FILESYSTEM' as ErrorCategoryType,
  SYSTEM: 'SYSTEM' as ErrorCategoryType,
  UNKNOWN: 'UNKNOWN' as ErrorCategoryType,
};

/**
 * Error severity classification (using type alias instead of enum)
 */
type ErrorSeverityLevel = 0 | 1 | 2 | 3 | 4;

const ErrorSeverity = {
  DEBUG: 0 as ErrorSeverityLevel,
  INFO: 1 as ErrorSeverityLevel,
  WARN: 2 as ErrorSeverityLevel,
  ERROR: 3 as ErrorSeverityLevel,
  FATAL: 4 as ErrorSeverityLevel,
};

/**
 * Standardized error structure for consistent error handling
 */
interface StandardizedApplicationErrorObject {
  errorMessage: string;                      // Human-readable description
  errorCode: string;                         // Machine-readable identifier
  errorCategory: ErrorCategoryType;          // System area affected (using type alias)
  errorSeverity: ErrorSeverityLevel;         // How critical the error is (using type alias)
  errorTimestamp: string;                    // When the error occurred
  errorContext: Record<string, unknown>;     // Additional relevant data
  errorStack?: string;                       // Stack trace if available
}

/**
 * Successful result from an operation
 */
interface OperationResultSuccess<DataType> {
  resultSuccessful: true;
  resultData: DataType;
}

/**
 * Failed result from an operation
 */
interface OperationResultFailure<ErrorType> {
  resultSuccessful: false;
  resultError: ErrorType;
}

/**
 * Combined result type for operations
 */
type OperationResult<DataType, ErrorType = StandardizedApplicationErrorObject> = 
  | OperationResultSuccess<DataType>
  | OperationResultFailure<ErrorType>;

/**
 * Configuration options for the tree generation operation
 */
interface TreeGenerationConfiguration {
  treeOutputFilePath: string;
  maximumDirectoryDepth: number;
  showHelpText: boolean;
}

/**
 * Definition of a gitignore pattern with parsing metadata
 */
interface GitignorePatternDefinition {
  patternText: string;
  isNegatedPattern: boolean;
  regexPattern: string;
}

/**
 * Result from the tree generation operation
 */
interface TreeGenerationResult {
  projectName: string;
  treeOutputFilePath: string;
  treeContentLength: number;
  maximumDepthApplied: number;
  generationTimestamp: string;
}

// -----------------------------------
// Constants
// -----------------------------------

/**
 * Default patterns to always ignore regardless of gitignore contents
 */
const DEFAULT_IGNORE_PATTERNS: string[] = [
  '.git', 
  'node_modules', 
  '.DS_Store', 
  'dist', 
  'build'
];

/**
 * Default output path for the generated tree
 */
const DEFAULT_OUTPUT_PATH = 'docs/tree.md';

/**
 * Help text displayed when requested
 */
const HELP_TEXT = `
Directory Tree Generator - Project structure visualization tool

Usage:
  node dist/utilities/generate.directory.tree.operation.js [output-path] [--depth=<number>] [--help]

Options:
  output-path      Custom file path for the tree output (default: docs/tree.md)
  --depth=<number> Maximum directory depth to display (default: unlimited)
  --help           Show this help message
`;

// -----------------------------------
// Utility Functions
// -----------------------------------

/**
 * Creates a standardized success result
 * 
 * @param data - The data to include in the success result
 * @returns A standardized success result object
 */
function createSuccessResult<DataType>(data: DataType): OperationResultSuccess<DataType> {
  return { resultSuccessful: true, resultData: data };
}

/**
 * Creates a standardized failure result
 * 
 * @param error - The error to include in the failure result
 * @returns A standardized failure result object
 */
function createFailureResult<ErrorType>(error: ErrorType): OperationResultFailure<ErrorType> {
  return { resultSuccessful: false, resultError: error };
}

/**
 * Creates a standardized error object
 * 
 * @param message - Human-readable error message
 * @param code - Machine-readable error code
 * @param category - Error category classification
 * @param severity - Error severity level
 * @param context - Additional context data
 * @returns A standardized error object
 */
function createStandardizedError(
  message: string,
  code: string,
  category: ErrorCategoryType, // Use the type alias
  severity: ErrorSeverityLevel, // Use the type alias
  context: Record<string, unknown> = {}
): StandardizedApplicationErrorObject {
  return {
    errorMessage: message,
    errorCode: code,
    errorCategory: category,
    errorSeverity: severity,
    errorTimestamp: new Date().toISOString(),
    errorContext: context
  };
}

/**
 * Converts an exception to a standardized error object
 * 
 * @param exception - The caught exception
 * @param defaultMessage - Fallback message if exception is not an Error object
 * @returns A standardized error object
 */
function wrapExceptionAsStandardizedError(
  exception: unknown,
  defaultMessage: string
): StandardizedApplicationErrorObject {
  const errorMessage = exception instanceof Error ? exception.message : defaultMessage;
  const errorStack = exception instanceof Error ? exception.stack : undefined;
  
  return {
    errorMessage,
    errorCode: 'UNEXPECTED_ERROR',
    errorCategory: ErrorCategory.UNKNOWN, // Use the constant object
    errorSeverity: ErrorSeverity.ERROR, // Use the constant object
    errorTimestamp: new Date().toISOString(),
    errorContext: { originalException: exception },
    errorStack
  };
}

// -----------------------------------
// Implementation Functions
// -----------------------------------

/**
 * Parses command line arguments to extract configuration options
 * 
 * @param commandLineArguments - Array of arguments from process.argv
 * @returns Configuration object for tree generation
 */
function parseCommandLineArguments(
  commandLineArguments: string[]
): TreeGenerationConfiguration {
  let treeOutputFilePath = DEFAULT_OUTPUT_PATH;
  let maximumDirectoryDepth = Infinity;
  let showHelpText = false;

  for (const argumentValue of commandLineArguments) {
    if (argumentValue === '--help') {
      showHelpText = true;
    } else if (argumentValue.startsWith('--depth=')) {
      const depthValue = argumentValue.split('=')[1];
      const parsedDepth = parseInt(depthValue, 10);
      
      if (isNaN(parsedDepth) || parsedDepth < 1) {
        console.error('Invalid depth value. Using unlimited depth.');
        maximumDirectoryDepth = Infinity;
      } else {
        maximumDirectoryDepth = parsedDepth;
      }
    } else if (!argumentValue.startsWith('--')) {
      // If it's not an option flag, assume it's the output path
      treeOutputFilePath = argumentValue;
    }
  }

  return {
    treeOutputFilePath,
    maximumDirectoryDepth,
    showHelpText
  };
}

/**
 * Loads and parses patterns from the .gitignore file
 * 
 * @returns Promise resolving to an array of parsed gitignore patterns
 */
async function loadGitignorePatternDefinitions(): Promise<OperationResult<GitignorePatternDefinition[]>> {
  try {
    const gitignoreContent = await fs.readFile('.gitignore', 'utf-8');
    
    const patternDefinitions = gitignoreContent
      .split('\n')
      .map(line => line.trim())
      // Remove comments, empty lines, and lines with just whitespace
      .filter(line => line && !line.startsWith('#') && line.trim() !== '')
      // Process each pattern
      .map(pattern => ({
        patternText: pattern.startsWith('!') ? pattern.slice(1) : pattern,
        isNegatedPattern: pattern.startsWith('!'),
        // Convert glob patterns to regex-compatible strings (simplified approach)
        regexPattern: pattern
          .replace(/\./g, '\\.') // Escape dots first
          .replace(/\*/g, '.*')  // Convert * to .*
          .replace(/\?/g, '.')   // Convert ? to .
          .replace(/\/$/, '(/.*)?') // Handle directory indicators
      }));
    
    return createSuccessResult(patternDefinitions);
  } catch (exceptionObject) {
    console.warn('No .gitignore file found, using default patterns only');
    return createSuccessResult([]);
  }
}

/**
 * Checks if a given file path should be ignored based on patterns
 * 
 * @param entryPath - The relative path to check
 * @param ignorePatternDefinitions - Array of parsed gitignore patterns
 * @returns Boolean indicating if the path should be ignored
 */
function checkPathShouldBeIgnored(
  entryPath: string, 
  ignorePatternDefinitions: GitignorePatternDefinition[]
): boolean {
  // Always check default patterns first
  if (DEFAULT_IGNORE_PATTERNS.some(pattern => entryPath.includes(pattern))) {
    return true;
  }

  let shouldBeIgnored = false;
  
  for (const { patternText, isNegatedPattern, regexPattern } of ignorePatternDefinitions) {
    // Convert the pattern to a proper regex
    const compiledRegexPattern = new RegExp(`^${regexPattern}$|/${regexPattern}$|/${regexPattern}/`);
    
    if (compiledRegexPattern.test(entryPath)) {
      // If it's a negation pattern (!pattern), this file should NOT be ignored
      // Otherwise, it should be ignored
      shouldBeIgnored = !isNegatedPattern;
    }
  }
  
  return shouldBeIgnored;
}

/**
 * Recursively generates a tree representation of the directory structure
 * 
 * @param directoryPath - Path to the directory to process
 * @param ignorePatternDefinitions - Array of gitignore pattern definitions
 * @param prefixString - Prefix string for the current level (used for indentation)
 * @param isLastEntry - Whether this is the last entry at the current level
 * @param relativePathString - Relative path from the root directory
 * @param currentDepthLevel - Current depth level in the traversal
 * @returns Promise resolving to the string representation of the tree
 */
async function generateDirectoryTreeRepresentation(
  directoryPath: string, 
  ignorePatternDefinitions: GitignorePatternDefinition[], 
  prefixString = '', 
  isLastEntry = true, 
  relativePathString = '', 
  currentDepthLevel = 0,
  maximumDepthLevel = Infinity
): Promise<OperationResult<string>> {
  try {
    const directoryEntries = await fs.readdir(directoryPath, { withFileTypes: true });
    let treeOutputContent = '';

    // Filter and sort entries
    const filteredEntries = directoryEntries
      .filter(entry => {
        const entryPath = path.join(relativePathString, entry.name);
        return !checkPathShouldBeIgnored(entryPath, ignorePatternDefinitions);
      })
      .sort((a, b) => {
        // Directories first, then files
        if (a.isDirectory() && !b.isDirectory()) return -1;
        if (!a.isDirectory() && b.isDirectory()) return 1;
        return a.name.localeCompare(b.name);
      });

    for (let entryIndex = 0; entryIndex < filteredEntries.length; entryIndex++) {
      const entryItem = filteredEntries[entryIndex];
      const isLastItem = entryIndex === filteredEntries.length - 1;
      const newPrefixString = prefixString + (isLastEntry ? '    ' : '│   ');
      const newRelativePath = path.join(relativePathString, entryItem.name);
      
      treeOutputContent += prefixString + (isLastItem ? '└── ' : '├── ') + entryItem.name + '\n';

      // Only traverse deeper if we haven't reached maximumDepthLevel
      if (entryItem.isDirectory() && currentDepthLevel < maximumDepthLevel) {
        const subTreeResult = await generateDirectoryTreeRepresentation(
          path.join(directoryPath, entryItem.name),
          ignorePatternDefinitions,
          newPrefixString,
          isLastItem,
          newRelativePath,
          currentDepthLevel + 1,
          maximumDepthLevel
        );
        
        if (subTreeResult.resultSuccessful) {
          treeOutputContent += subTreeResult.resultData;
        } else {
          return subTreeResult; // Propagate error
        }
      }
    }

    return createSuccessResult(treeOutputContent);
  } catch (exceptionObject) {
    return createFailureResult(
      wrapExceptionAsStandardizedError(
        exceptionObject,
        `Failed to generate tree for directory: ${directoryPath}`
      )
    );
  }
}

/**
 * Ensures the directory for the output file exists, creating it if needed
 * 
 * @param directoryPath - Path to the directory to check/create
 * @returns Promise resolving to operation result
 */
async function ensureDirectoryExists(
  directoryPath: string
): Promise<OperationResult<boolean>> {
  try {
    await fs.access(directoryPath);
    return createSuccessResult(true);
  } catch {
    try {
      await fs.mkdir(directoryPath, { recursive: true });
      console.log(`Creating directory: ${directoryPath}`);
      return createSuccessResult(true);
    } catch (exceptionObject) {
      return createFailureResult(
        wrapExceptionAsStandardizedError(
          exceptionObject,
          `Failed to create directory: ${directoryPath}`
        )
      );
    }
  }
}

/**
 * Writes the generated tree content to a markdown file
 * 
 * @param projectName - Name of the project
 * @param treeContent - Generated tree content
 * @param outputFilePath - Path where the output file should be written
 * @param maximumDepthValue - Maximum depth value that was applied
 * @returns Promise resolving to operation result
 */
async function writeTreeContentToFile(
  projectName: string,
  treeContent: string,
  outputFilePath: string,
  maximumDepthValue: number
): Promise<OperationResult<TreeGenerationResult>> {
  try {
    const rootDirectoryPath = process.cwd();
    const outputDirectoryPath = path.dirname(path.resolve(rootDirectoryPath, outputFilePath));
    
    // Ensure output directory exists
    const directoryResult = await ensureDirectoryExists(outputDirectoryPath);
    if (!directoryResult.resultSuccessful) {
      return directoryResult;
    }

    // Format the timestamp
    const timestamp = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
    
    // Format the markdown content
    const markdownContent = `# ${projectName} - Directory Structure

Generated on: ${timestamp}

${maximumDepthValue !== Infinity ? `_Depth limited to ${maximumDepthValue} levels_\n\n` : ''}
\`\`\`
${projectName}
${treeContent}
\`\`\`

_Note: This tree excludes files and directories matched by .gitignore and common patterns like node_modules._
`;

    // Write the content to the file
    await fs.writeFile(
      path.resolve(rootDirectoryPath, outputFilePath),
      markdownContent
    );
    
    return createSuccessResult({
      projectName,
      treeOutputFilePath: outputFilePath,
      treeContentLength: treeContent.length,
      maximumDepthApplied: maximumDepthValue,
      generationTimestamp: timestamp
    });
  } catch (exceptionObject) {
    return createFailureResult(
      wrapExceptionAsStandardizedError(
        exceptionObject,
        `Failed to write tree to file: ${outputFilePath}`
      )
    );
  }
}

/**
 * Main operation function that orchestrates the tree generation process
 * 
 * @returns Promise that resolves when the operation completes
 */
async function generateProjectDirectoryTree(): Promise<void> {
  try {
    // Parse command line arguments
    const commandLineArguments = process.argv.slice(2);
    const configurationSettings = parseCommandLineArguments(commandLineArguments);
    
    // Display help if requested
    if (configurationSettings.showHelpText) {
      console.log(HELP_TEXT);
      process.exit(0);
    }
    
    const rootDirectoryPath = process.cwd();
    const projectName = path.basename(rootDirectoryPath);
    
    // Load gitignore patterns
    const ignorePatternResult = await loadGitignorePatternDefinitions();
    if (!ignorePatternResult.resultSuccessful) {
      throw new Error(`Failed to load gitignore patterns: ${ignorePatternResult.resultError.errorMessage}`);
    }
    
    const ignorePatternDefinitions = ignorePatternResult.resultData;
    
    console.log(`Generating directory tree for: ${projectName}`);
    console.log(`Output path: ${configurationSettings.treeOutputFilePath}`);
    
    if (configurationSettings.maximumDirectoryDepth !== Infinity) {
      console.log(`Maximum depth: ${configurationSettings.maximumDirectoryDepth}`);
    }
    
    // Generate the tree structure
    const treeGenerationResult = await generateDirectoryTreeRepresentation(
      rootDirectoryPath, 
      ignorePatternDefinitions, 
      '', 
      true, 
      '', 
      0,
      configurationSettings.maximumDirectoryDepth
    );
    
    if (!treeGenerationResult.resultSuccessful) {
      throw new Error(`Failed to generate tree: ${treeGenerationResult.resultError.errorMessage}`);
    }
    
    // Write the tree to a file
    const writeResult = await writeTreeContentToFile(
      projectName,
      treeGenerationResult.resultData,
      configurationSettings.treeOutputFilePath,
      configurationSettings.maximumDirectoryDepth
    );
    
    if (!writeResult.resultSuccessful) {
      throw new Error(`Failed to write tree: ${writeResult.resultError.errorMessage}`);
    }
    
    console.log(`✓ Successfully generated tree structure in ${configurationSettings.treeOutputFilePath}`);
  } catch (exceptionObject) {
    const standardizedError = wrapExceptionAsStandardizedError(
      exceptionObject,
      'Unhandled error during tree generation'
    );
    
    console.error(`× Error generating tree: ${standardizedError.errorMessage}`);
    process.exit(1);
  }
}

// -----------------------------------
// Script Execution
// -----------------------------------

// Execute the main operation function
generateProjectDirectoryTree();

```

--------------------------------------------------------------------------------
/src/utils/internal/logger.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides a singleton Logger class that wraps Winston for file logging
 * and supports sending MCP (Model Context Protocol) `notifications/message`.
 * It handles different log levels compliant with RFC 5424 and MCP specifications.
 * @module src/utils/internal/logger
 */
import fs from "fs";
import path from "path";
import winston from "winston";
import TransportStream from "winston-transport";
import { config } from "../../config/index.js";
import { RequestContext } from "./requestContext.js";

/**
 * Defines the supported logging levels based on RFC 5424 Syslog severity levels,
 * as used by the Model Context Protocol (MCP).
 * Levels are: 'debug'(7), 'info'(6), 'notice'(5), 'warning'(4), 'error'(3), 'crit'(2), 'alert'(1), 'emerg'(0).
 * Lower numeric values indicate higher severity.
 */
export type McpLogLevel =
  | "debug"
  | "info"
  | "notice"
  | "warning"
  | "error"
  | "crit"
  | "alert"
  | "emerg";

/**
 * Numeric severity mapping for MCP log levels (lower is more severe).
 * @private
 */
const mcpLevelSeverity: Record<McpLogLevel, number> = {
  emerg: 0,
  alert: 1,
  crit: 2,
  error: 3,
  warning: 4,
  notice: 5,
  info: 6,
  debug: 7,
};

/**
 * Maps MCP log levels to Winston's core levels for file logging.
 * @private
 */
const mcpToWinstonLevel: Record<
  McpLogLevel,
  "debug" | "info" | "warn" | "error"
> = {
  debug: "debug",
  info: "info",
  notice: "info",
  warning: "warn",
  error: "error",
  crit: "error",
  alert: "error",
  emerg: "error",
};

/**
 * Interface for a more structured error object, primarily for formatting console logs.
 * @private
 */
interface ErrorWithMessageAndStack {
  message?: string;
  stack?: string;
  [key: string]: any;
}

/**
 * Interface for the payload of an MCP log notification.
 * This structure is used when sending log data via MCP `notifications/message`.
 */
export interface McpLogPayload {
  message: string;
  context?: RequestContext;
  error?: {
    message: string;
    stack?: string;
  };
  [key: string]: any;
}

/**
 * Type for the `data` parameter of the `McpNotificationSender` function.
 */
export type McpNotificationData = McpLogPayload | Record<string, unknown>;

/**
 * Defines the signature for a function that can send MCP log notifications.
 * This function is typically provided by the MCP server instance.
 * @param level - The severity level of the log message.
 * @param data - The payload of the log notification.
 * @param loggerName - An optional name or identifier for the logger/server.
 */
export type McpNotificationSender = (
  level: McpLogLevel,
  data: McpNotificationData,
  loggerName?: string,
) => void;

// The logsPath from config is already resolved and validated by src/config/index.ts
const resolvedLogsDir = config.logsPath;
const isLogsDirSafe = !!resolvedLogsDir; // If logsPath is set, it's considered safe by config logic.

/**
 * Creates the Winston console log format.
 * @returns The Winston log format for console output.
 * @private
 */
function createWinstonConsoleFormat(): winston.Logform.Format {
  return winston.format.combine(
    winston.format.colorize(),
    winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
    winston.format.printf(({ timestamp, level, message, ...meta }) => {
      let metaString = "";
      const metaCopy = { ...meta };
      if (metaCopy.error && typeof metaCopy.error === "object") {
        const errorObj = metaCopy.error as ErrorWithMessageAndStack;
        if (errorObj.message) metaString += `\n  Error: ${errorObj.message}`;
        if (errorObj.stack)
          metaString += `\n  Stack: ${String(errorObj.stack)
            .split("\n")
            .map((l: string) => `    ${l}`)
            .join("\n")}`;
        delete metaCopy.error;
      }
      if (Object.keys(metaCopy).length > 0) {
        try {
          const remainingMetaJson = JSON.stringify(metaCopy, null, 2);
          if (remainingMetaJson !== "{}")
            metaString += `\n  Meta: ${remainingMetaJson}`;
        } catch (stringifyError: unknown) {
          const errorMessage =
            stringifyError instanceof Error
              ? stringifyError.message
              : String(stringifyError);
          metaString += `\n  Meta: [Error stringifying metadata: ${errorMessage}]`;
        }
      }
      return `${timestamp} ${level}: ${message}${metaString}`;
    }),
  );
}

/**
 * Singleton Logger class that wraps Winston for robust logging.
 * Supports file logging, conditional console logging, and MCP notifications.
 */
export class Logger {
  private static instance: Logger;
  private winstonLogger?: winston.Logger;
  private initialized = false;
  private mcpNotificationSender?: McpNotificationSender;
  private currentMcpLevel: McpLogLevel = "info";
  private currentWinstonLevel: "debug" | "info" | "warn" | "error" = "info";

  private readonly MCP_NOTIFICATION_STACK_TRACE_MAX_LENGTH = 1024;
  private readonly LOG_FILE_MAX_SIZE = 5 * 1024 * 1024; // 5MB
  private readonly LOG_MAX_FILES = 5;

  /** @private */
  private constructor() {}

  /**
   * Initializes the Winston logger instance.
   * Should be called once at application startup.
   * @param level - The initial minimum MCP log level.
   */
  public async initialize(level: McpLogLevel = "info"): Promise<void> {
    if (this.initialized) {
      this.warning("Logger already initialized.", {
        loggerSetup: true,
        requestId: "logger-init",
        timestamp: new Date().toISOString(),
      });
      return;
    }
    this.currentMcpLevel = level;
    this.currentWinstonLevel = mcpToWinstonLevel[level];

    let logsDirCreatedMessage: string | null = null; // This message is now informational as creation is handled by config

    if (isLogsDirSafe) {
      // Directory creation is handled by config/index.ts ensureDirectory.
      // We can log if it was newly created by checking if it existed before config ran,
      // but that's complex. For now, we assume config handled it.
      // If resolvedLogsDir is set, config ensures it exists.
      if (!fs.existsSync(resolvedLogsDir)) {
        // This case should ideally not be hit if config.logsPath is correctly set up and validated.
        // However, if it somehow occurs (e.g. dir deleted after config init but before logger init),
        // we attempt to create it.
        try {
          await fs.promises.mkdir(resolvedLogsDir, { recursive: true });
          logsDirCreatedMessage = `Re-created logs directory (should have been created by config): ${resolvedLogsDir}`;
        } catch (err: unknown) {
          if (process.stdout.isTTY) {
            const errorMessage =
              err instanceof Error ? err.message : String(err);
            console.error(
              `Error creating logs directory at ${resolvedLogsDir}: ${errorMessage}. File logging disabled.`,
            );
          }
          throw err; // Critical if logs dir cannot be ensured
        }
      }
    }

    const fileFormat = winston.format.combine(
      winston.format.timestamp(),
      winston.format.errors({ stack: true }),
      winston.format.json(),
    );

    const transports: TransportStream[] = [];
    const fileTransportOptions = {
      format: fileFormat,
      maxsize: this.LOG_FILE_MAX_SIZE,
      maxFiles: this.LOG_MAX_FILES,
      tailable: true,
    };

    if (isLogsDirSafe) {
      transports.push(
        new winston.transports.File({
          filename: path.join(resolvedLogsDir, "error.log"),
          level: "error",
          ...fileTransportOptions,
        }),
        new winston.transports.File({
          filename: path.join(resolvedLogsDir, "warn.log"),
          level: "warn",
          ...fileTransportOptions,
        }),
        new winston.transports.File({
          filename: path.join(resolvedLogsDir, "info.log"),
          level: "info",
          ...fileTransportOptions,
        }),
        new winston.transports.File({
          filename: path.join(resolvedLogsDir, "debug.log"),
          level: "debug",
          ...fileTransportOptions,
        }),
        new winston.transports.File({
          filename: path.join(resolvedLogsDir, "combined.log"),
          ...fileTransportOptions,
        }),
      );
    } else {
      if (process.stdout.isTTY) {
        console.warn(
          "File logging disabled as logsPath is not configured or invalid.",
        );
      }
    }

    this.winstonLogger = winston.createLogger({
      level: this.currentWinstonLevel,
      transports,
      exitOnError: false,
    });

    // Configure console transport after Winston logger is created
    const consoleStatus = this._configureConsoleTransport();

    const initialContext: RequestContext = {
      loggerSetup: true,
      requestId: "logger-init-deferred",
      timestamp: new Date().toISOString(),
    };
    if (logsDirCreatedMessage) {
      // Log if we had to re-create it
      this.info(logsDirCreatedMessage, initialContext);
    }
    if (consoleStatus.message) {
      this.info(consoleStatus.message, initialContext);
    }

    this.initialized = true;
    this.info(
      `Logger initialized. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${consoleStatus.enabled ? "enabled" : "disabled"}`,
      {
        loggerSetup: true,
        requestId: "logger-post-init",
        timestamp: new Date().toISOString(),
        logsPathUsed: resolvedLogsDir,
      },
    );
  }

  /**
   * Sets the function used to send MCP 'notifications/message'.
   * @param sender - The function to call for sending notifications, or undefined to disable.
   */
  public setMcpNotificationSender(
    sender: McpNotificationSender | undefined,
  ): void {
    this.mcpNotificationSender = sender;
    const status = sender ? "enabled" : "disabled";
    this.info(`MCP notification sending ${status}.`, {
      loggerSetup: true,
      requestId: "logger-set-sender",
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * Dynamically sets the minimum logging level.
   * @param newLevel - The new minimum MCP log level to set.
   */
  public setLevel(newLevel: McpLogLevel): void {
    const setLevelContext: RequestContext = {
      loggerSetup: true,
      requestId: "logger-set-level",
      timestamp: new Date().toISOString(),
    };
    if (!this.ensureInitialized()) {
      if (process.stdout.isTTY) {
        console.error("Cannot set level: Logger not initialized.");
      }
      return;
    }
    if (!(newLevel in mcpLevelSeverity)) {
      this.warning(
        `Invalid MCP log level provided: ${newLevel}. Level not changed.`,
        setLevelContext,
      );
      return;
    }

    const oldLevel = this.currentMcpLevel;
    this.currentMcpLevel = newLevel;
    this.currentWinstonLevel = mcpToWinstonLevel[newLevel];
    if (this.winstonLogger) {
      // Ensure winstonLogger is defined
      this.winstonLogger.level = this.currentWinstonLevel;
    }

    const consoleStatus = this._configureConsoleTransport();

    if (oldLevel !== newLevel) {
      this.info(
        `Log level changed. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${consoleStatus.enabled ? "enabled" : "disabled"}`,
        setLevelContext,
      );
      if (
        consoleStatus.message &&
        consoleStatus.message !== "Console logging status unchanged."
      ) {
        this.info(consoleStatus.message, setLevelContext);
      }
    }
  }

  /**
   * Configures the console transport based on the current log level and TTY status.
   * Adds or removes the console transport as needed.
   * @returns {{ enabled: boolean, message: string | null }} Status of console logging.
   * @private
   */
  private _configureConsoleTransport(): {
    enabled: boolean;
    message: string | null;
  } {
    if (!this.winstonLogger) {
      return {
        enabled: false,
        message: "Cannot configure console: Winston logger not initialized.",
      };
    }

    const consoleTransport = this.winstonLogger.transports.find(
      (t) => t instanceof winston.transports.Console,
    );
    const shouldHaveConsole =
      this.currentMcpLevel === "debug" && process.stdout.isTTY;
    let message: string | null = null;

    if (shouldHaveConsole && !consoleTransport) {
      const consoleFormat = createWinstonConsoleFormat();
      this.winstonLogger.add(
        new winston.transports.Console({
          level: "debug", // Console always logs debug if enabled
          format: consoleFormat,
        }),
      );
      message = "Console logging enabled (level: debug, stdout is TTY).";
    } else if (!shouldHaveConsole && consoleTransport) {
      this.winstonLogger.remove(consoleTransport);
      message = "Console logging disabled (level not debug or stdout not TTY).";
    } else {
      message = "Console logging status unchanged.";
    }
    return { enabled: shouldHaveConsole, message };
  }

  /**
   * Gets the singleton instance of the Logger.
   * @returns The singleton Logger instance.
   */
  public static getInstance(): Logger {
    if (!Logger.instance) {
      Logger.instance = new Logger();
    }
    return Logger.instance;
  }

  /**
   * Ensures the logger has been initialized.
   * @returns True if initialized, false otherwise.
   * @private
   */
  private ensureInitialized(): boolean {
    if (!this.initialized || !this.winstonLogger) {
      if (process.stdout.isTTY) {
        console.warn("Logger not initialized; message dropped.");
      }
      return false;
    }
    return true;
  }

  /**
   * Centralized log processing method.
   * @param level - The MCP severity level of the message.
   * @param msg - The main log message.
   * @param context - Optional request context for the log.
   * @param error - Optional error object associated with the log.
   * @private
   */
  private log(
    level: McpLogLevel,
    msg: string,
    context?: RequestContext,
    error?: Error,
  ): void {
    if (!this.ensureInitialized()) return;
    if (mcpLevelSeverity[level] > mcpLevelSeverity[this.currentMcpLevel]) {
      return; // Do not log if message level is less severe than currentMcpLevel
    }

    const logData: Record<string, unknown> = { ...context };
    const winstonLevel = mcpToWinstonLevel[level];

    if (error) {
      this.winstonLogger!.log(winstonLevel, msg, { ...logData, error });
    } else {
      this.winstonLogger!.log(winstonLevel, msg, logData);
    }

    if (this.mcpNotificationSender) {
      const mcpDataPayload: McpLogPayload = { message: msg };
      if (context && Object.keys(context).length > 0)
        mcpDataPayload.context = context;
      if (error) {
        mcpDataPayload.error = { message: error.message };
        // Include stack trace in debug mode for MCP notifications, truncated for brevity
        if (this.currentMcpLevel === "debug" && error.stack) {
          mcpDataPayload.error.stack = error.stack.substring(
            0,
            this.MCP_NOTIFICATION_STACK_TRACE_MAX_LENGTH,
          );
        }
      }
      try {
        const serverName =
          config?.mcpServerName ?? "MCP_SERVER_NAME_NOT_CONFIGURED";
        this.mcpNotificationSender(level, mcpDataPayload, serverName);
      } catch (sendError: unknown) {
        const errorMessage =
          sendError instanceof Error ? sendError.message : String(sendError);
        const internalErrorContext: RequestContext = {
          requestId: context?.requestId || "logger-internal-error",
          timestamp: new Date().toISOString(),
          originalLevel: level,
          originalMessage: msg,
          sendError: errorMessage,
          mcpPayload: JSON.stringify(mcpDataPayload).substring(0, 500), // Log a preview
        };
        this.winstonLogger!.error(
          "Failed to send MCP log notification",
          internalErrorContext,
        );
      }
    }
  }

  /** Logs a message at the 'debug' level. */
  public debug(msg: string, context?: RequestContext): void {
    this.log("debug", msg, context);
  }

  /** Logs a message at the 'info' level. */
  public info(msg: string, context?: RequestContext): void {
    this.log("info", msg, context);
  }

  /** Logs a message at the 'notice' level. */
  public notice(msg: string, context?: RequestContext): void {
    this.log("notice", msg, context);
  }

  /** Logs a message at the 'warning' level. */
  public warning(msg: string, context?: RequestContext): void {
    this.log("warning", msg, context);
  }

  /**
   * Logs a message at the 'error' level.
   * @param msg - The main log message.
   * @param err - Optional. Error object or RequestContext.
   * @param context - Optional. RequestContext if `err` is an Error.
   */
  public error(
    msg: string,
    err?: Error | RequestContext,
    context?: RequestContext,
  ): void {
    const errorObj = err instanceof Error ? err : undefined;
    const actualContext = err instanceof Error ? context : err;
    this.log("error", msg, actualContext, errorObj);
  }

  /**
   * Logs a message at the 'crit' (critical) level.
   * @param msg - The main log message.
   * @param err - Optional. Error object or RequestContext.
   * @param context - Optional. RequestContext if `err` is an Error.
   */
  public crit(
    msg: string,
    err?: Error | RequestContext,
    context?: RequestContext,
  ): void {
    const errorObj = err instanceof Error ? err : undefined;
    const actualContext = err instanceof Error ? context : err;
    this.log("crit", msg, actualContext, errorObj);
  }

  /**
   * Logs a message at the 'alert' level.
   * @param msg - The main log message.
   * @param err - Optional. Error object or RequestContext.
   * @param context - Optional. RequestContext if `err` is an Error.
   */
  public alert(
    msg: string,
    err?: Error | RequestContext,
    context?: RequestContext,
  ): void {
    const errorObj = err instanceof Error ? err : undefined;
    const actualContext = err instanceof Error ? context : err;
    this.log("alert", msg, actualContext, errorObj);
  }

  /**
   * Logs a message at the 'emerg' (emergency) level.
   * @param msg - The main log message.
   * @param err - Optional. Error object or RequestContext.
   * @param context - Optional. RequestContext if `err` is an Error.
   */
  public emerg(
    msg: string,
    err?: Error | RequestContext,
    context?: RequestContext,
  ): void {
    const errorObj = err instanceof Error ? err : undefined;
    const actualContext = err instanceof Error ? context : err;
    this.log("emerg", msg, actualContext, errorObj);
  }

  /**
   * Logs a message at the 'emerg' (emergency) level, typically for fatal errors.
   * @param msg - The main log message.
   * @param err - Optional. Error object or RequestContext.
   * @param context - Optional. RequestContext if `err` is an Error.
   */
  public fatal(
    msg: string,
    err?: Error | RequestContext,
    context?: RequestContext,
  ): void {
    const errorObj = err instanceof Error ? err : undefined;
    const actualContext = err instanceof Error ? context : err;
    this.log("emerg", msg, actualContext, errorObj);
  }
}

/**
 * The singleton instance of the Logger.
 * Use this instance for all logging operations.
 */
export const logger = Logger.getInstance();

```

--------------------------------------------------------------------------------
/src/utils/security/sanitization.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides a comprehensive `Sanitization` class for various input cleaning and validation tasks.
 * This module includes utilities for sanitizing HTML, strings, URLs, file paths, JSON, numbers,
 * and for redacting sensitive information from data intended for logging.
 * @module src/utils/security/sanitization
 */
import path from "path";
import sanitizeHtml from "sanitize-html";
import validator from "validator";
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
import { logger, requestContextService } from "../index.js";

/**
 * Defines options for path sanitization to control how file paths are processed and validated.
 */
export interface PathSanitizeOptions {
  /** If provided, restricts sanitized paths to be relative to this directory. */
  rootDir?: string;
  /** If true, normalizes Windows backslashes to POSIX forward slashes. */
  toPosix?: boolean;
  /** If true, absolute paths are permitted (subject to `rootDir`). Default: false. */
  allowAbsolute?: boolean;
}

/**
 * Contains information about a path sanitization operation.
 */
export interface SanitizedPathInfo {
  /** The final sanitized and normalized path string. */
  sanitizedPath: string;
  /** The original path string before any processing. */
  originalInput: string;
  /** True if the input path was absolute after initial normalization. */
  wasAbsolute: boolean;
  /** True if an absolute path was converted to relative due to `allowAbsolute: false`. */
  convertedToRelative: boolean;
  /** The effective options used for sanitization, including defaults. */
  optionsUsed: PathSanitizeOptions;
}

/**
 * Defines options for context-specific string sanitization.
 */
export interface SanitizeStringOptions {
  /** The context in which the string will be used. 'javascript' is disallowed. */
  context?: "text" | "html" | "attribute" | "url" | "javascript";
  /** Custom allowed HTML tags if `context` is 'html'. */
  allowedTags?: string[];
  /** Custom allowed HTML attributes if `context` is 'html'. */
  allowedAttributes?: Record<string, string[]>;
}

/**
 * Configuration options for HTML sanitization, mirroring `sanitize-html` library options.
 */
export interface HtmlSanitizeConfig {
  /** An array of allowed HTML tag names. */
  allowedTags?: string[];
  /** Specifies allowed attributes, either globally or per tag. */
  allowedAttributes?: sanitizeHtml.IOptions["allowedAttributes"];
  /** If true, HTML comments are preserved. */
  preserveComments?: boolean;
  /** Custom functions to transform tags during sanitization. */
  transformTags?: sanitizeHtml.IOptions["transformTags"];
}

/**
 * A singleton class providing various methods for input sanitization.
 * Aims to protect against common vulnerabilities like XSS and path traversal.
 */
export class Sanitization {
  /** @private */
  private static instance: Sanitization;

  /**
   * Default list of field names considered sensitive for log redaction.
   * Case-insensitive matching is applied.
   * @private
   */
  private sensitiveFields: string[] = [
    "password",
    "token",
    "secret",
    "key",
    "apiKey",
    "auth",
    "credential",
    "jwt",
    "ssn",
    "credit",
    "card",
    "cvv",
    "authorization",
  ];

  /**
   * Default configuration for HTML sanitization.
   * @private
   */
  private defaultHtmlSanitizeConfig: HtmlSanitizeConfig = {
    allowedTags: [
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6",
      "p",
      "a",
      "ul",
      "ol",
      "li",
      "b",
      "i",
      "strong",
      "em",
      "strike",
      "code",
      "hr",
      "br",
      "div",
      "table",
      "thead",
      "tbody",
      "tr",
      "th",
      "td",
      "pre",
    ],
    allowedAttributes: {
      a: ["href", "name", "target"],
      img: ["src", "alt", "title", "width", "height"],
      "*": ["class", "id", "style"],
    },
    preserveComments: false,
  };

  /** @private */
  private constructor() {}

  /**
   * Retrieves the singleton instance of the `Sanitization` class.
   * @returns The singleton `Sanitization` instance.
   */
  public static getInstance(): Sanitization {
    if (!Sanitization.instance) {
      Sanitization.instance = new Sanitization();
    }
    return Sanitization.instance;
  }

  /**
   * Sets or extends the list of sensitive field names for log sanitization.
   * @param fields - An array of field names to add to the sensitive list.
   */
  public setSensitiveFields(fields: string[]): void {
    this.sensitiveFields = [
      ...new Set([
        ...this.sensitiveFields,
        ...fields.map((f) => f.toLowerCase()),
      ]),
    ];
    const logContext = requestContextService.createRequestContext({
      operation: "Sanitization.setSensitiveFields",
      newSensitiveFieldCount: this.sensitiveFields.length,
    });
    logger.debug(
      "Updated sensitive fields list for log sanitization",
      logContext,
    );
  }

  /**
   * Gets a copy of the current list of sensitive field names.
   * @returns An array of sensitive field names.
   */
  public getSensitiveFields(): string[] {
    return [...this.sensitiveFields];
  }

  /**
   * Sanitizes an HTML string by removing potentially malicious tags and attributes.
   * @param input - The HTML string to sanitize.
   * @param config - Optional custom configuration for `sanitize-html`.
   * @returns The sanitized HTML string. Returns an empty string if input is falsy.
   */
  public sanitizeHtml(input: string, config?: HtmlSanitizeConfig): string {
    if (!input) return "";
    const effectiveConfig = { ...this.defaultHtmlSanitizeConfig, ...config };
    const options: sanitizeHtml.IOptions = {
      allowedTags: effectiveConfig.allowedTags,
      allowedAttributes: effectiveConfig.allowedAttributes,
      transformTags: effectiveConfig.transformTags,
    };
    if (effectiveConfig.preserveComments) {
      options.allowedTags = [...(options.allowedTags || []), "!--"];
    }
    return sanitizeHtml(input, options);
  }

  /**
   * Sanitizes a string based on its intended context (e.g., HTML, URL, text).
   * **Important:** `context: 'javascript'` is disallowed due to security risks.
   *
   * @param input - The string to sanitize.
   * @param options - Options specifying the sanitization context.
   * @returns The sanitized string. Returns an empty string if input is falsy.
   * @throws {McpError} If `options.context` is 'javascript', or URL validation fails.
   */
  public sanitizeString(
    input: string,
    options: SanitizeStringOptions = {},
  ): string {
    if (!input) return "";

    switch (options.context) {
      case "html":
        return this.sanitizeHtml(input, {
          allowedTags: options.allowedTags,
          allowedAttributes: options.allowedAttributes
            ? this.convertAttributesFormat(options.allowedAttributes)
            : undefined,
        });
      case "attribute":
        return sanitizeHtml(input, { allowedTags: [], allowedAttributes: {} });
      case "url":
        if (
          !validator.isURL(input, {
            protocols: ["http", "https"],
            require_protocol: true,
            require_host: true,
          })
        ) {
          logger.warning(
            "Potentially invalid URL detected during string sanitization (context: url)",
            requestContextService.createRequestContext({
              operation: "Sanitization.sanitizeString.urlWarning",
              invalidUrlAttempt: input,
            }),
          );
          return "";
        }
        return validator.trim(input);
      case "javascript":
        logger.error(
          "Attempted JavaScript sanitization via sanitizeString, which is disallowed.",
          requestContextService.createRequestContext({
            operation: "Sanitization.sanitizeString.jsAttempt",
            inputSnippet: input.substring(0, 50),
          }),
        );
        throw new McpError(
          BaseErrorCode.VALIDATION_ERROR,
          "JavaScript sanitization is not supported through sanitizeString due to security risks.",
        );
      case "text":
      default:
        return sanitizeHtml(input, { allowedTags: [], allowedAttributes: {} });
    }
  }

  /**
   * Converts attribute format for `sanitizeHtml`.
   * @param attrs - Attributes in `{ tagName: ['attr1'] }` format.
   * @returns Attributes in `sanitize-html` expected format.
   * @private
   */
  private convertAttributesFormat(
    attrs: Record<string, string[]>,
  ): sanitizeHtml.IOptions["allowedAttributes"] {
    return attrs;
  }

  /**
   * Sanitizes a URL string by validating its format and protocol.
   * @param input - The URL string to sanitize.
   * @param allowedProtocols - Array of allowed URL protocols. Default: `['http', 'https']`.
   * @returns The sanitized and trimmed URL string.
   * @throws {McpError} If the URL is invalid or uses a disallowed protocol.
   */
  public sanitizeUrl(
    input: string,
    allowedProtocols: string[] = ["http", "https"],
  ): string {
    try {
      const trimmedInput = input.trim();
      if (
        !validator.isURL(trimmedInput, {
          protocols: allowedProtocols,
          require_protocol: true,
          require_host: true,
        })
      ) {
        throw new Error("Invalid URL format or protocol not in allowed list.");
      }
      if (trimmedInput.toLowerCase().startsWith("javascript:")) {
        throw new Error("JavaScript pseudo-protocol is not allowed in URLs.");
      }
      return trimmedInput;
    } catch (error) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        error instanceof Error
          ? error.message
          : "Invalid or unsafe URL provided.",
        { input },
      );
    }
  }

  /**
   * Sanitizes a file path to prevent path traversal and normalize format.
   * @param input - The file path string to sanitize.
   * @param options - Options to control sanitization behavior.
   * @returns An object with the sanitized path and sanitization metadata.
   * @throws {McpError} If the path is invalid or unsafe.
   */
  public sanitizePath(
    input: string,
    options: PathSanitizeOptions = {},
  ): SanitizedPathInfo {
    const originalInput = input;
    const effectiveOptions: PathSanitizeOptions = {
      toPosix: options.toPosix ?? false,
      allowAbsolute: options.allowAbsolute ?? false,
      rootDir: options.rootDir ? path.resolve(options.rootDir) : undefined,
    };

    let wasAbsoluteInitially = false;
    let convertedToRelative = false;

    try {
      if (!input || typeof input !== "string")
        throw new Error("Invalid path input: must be a non-empty string.");
      if (input.includes("\0"))
        throw new Error("Path contains null byte, which is disallowed.");

      let normalized = path.normalize(input);
      wasAbsoluteInitially = path.isAbsolute(normalized);

      if (effectiveOptions.toPosix) {
        normalized = normalized.replace(/\\/g, "/");
      }

      let finalSanitizedPath: string;

      if (effectiveOptions.rootDir) {
        const fullPath = path.resolve(effectiveOptions.rootDir, normalized);
        if (
          !fullPath.startsWith(effectiveOptions.rootDir + path.sep) &&
          fullPath !== effectiveOptions.rootDir
        ) {
          throw new Error(
            "Path traversal detected: attempts to escape the defined root directory.",
          );
        }
        finalSanitizedPath = path.relative(effectiveOptions.rootDir, fullPath);
        finalSanitizedPath =
          finalSanitizedPath === "" ? "." : finalSanitizedPath;
        if (
          path.isAbsolute(finalSanitizedPath) &&
          !effectiveOptions.allowAbsolute
        ) {
          throw new Error(
            "Path resolved to absolute outside root when absolute paths are disallowed.",
          );
        }
      } else {
        if (path.isAbsolute(normalized)) {
          if (!effectiveOptions.allowAbsolute) {
            finalSanitizedPath = normalized.replace(
              /^(?:[A-Za-z]:)?[/\\]+/,
              "",
            );
            convertedToRelative = true;
          } else {
            finalSanitizedPath = normalized;
          }
        } else {
          const resolvedAgainstCwd = path.resolve(normalized);
          const currentWorkingDir = path.resolve(".");
          if (
            !resolvedAgainstCwd.startsWith(currentWorkingDir + path.sep) &&
            resolvedAgainstCwd !== currentWorkingDir
          ) {
            throw new Error(
              "Relative path traversal detected (escapes current working directory context).",
            );
          }
          finalSanitizedPath = normalized;
        }
      }

      return {
        sanitizedPath: finalSanitizedPath,
        originalInput,
        wasAbsolute: wasAbsoluteInitially,
        convertedToRelative:
          wasAbsoluteInitially &&
          !path.isAbsolute(finalSanitizedPath) &&
          !effectiveOptions.allowAbsolute,
        optionsUsed: effectiveOptions,
      };
    } catch (error) {
      logger.warning(
        "Path sanitization error",
        requestContextService.createRequestContext({
          operation: "Sanitization.sanitizePath.error",
          originalPathInput: originalInput,
          pathOptionsUsed: effectiveOptions,
          errorMessage: error instanceof Error ? error.message : String(error),
        }),
      );
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        error instanceof Error
          ? error.message
          : "Invalid or unsafe path provided.",
        { input: originalInput },
      );
    }
  }

  /**
   * Sanitizes a JSON string by parsing it to validate its format.
   * Optionally checks if the JSON string exceeds a maximum allowed size.
   * @template T The expected type of the parsed JSON object. Defaults to `unknown`.
   * @param input - The JSON string to sanitize/validate.
   * @param maxSize - Optional maximum allowed size of the JSON string in bytes.
   * @returns The parsed JavaScript object.
   * @throws {McpError} If input is not a string, too large, or invalid JSON.
   */
  public sanitizeJson<T = unknown>(input: string, maxSize?: number): T {
    try {
      if (typeof input !== "string")
        throw new Error("Invalid input: expected a JSON string.");
      if (maxSize !== undefined && Buffer.byteLength(input, "utf8") > maxSize) {
        throw new McpError(
          BaseErrorCode.VALIDATION_ERROR,
          `JSON string exceeds maximum allowed size of ${maxSize} bytes.`,
          { actualSize: Buffer.byteLength(input, "utf8"), maxSize },
        );
      }
      return JSON.parse(input) as T;
    } catch (error) {
      if (error instanceof McpError) throw error;
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        error instanceof Error ? error.message : "Invalid JSON format.",
        {
          inputPreview:
            input.length > 100 ? `${input.substring(0, 100)}...` : input,
        },
      );
    }
  }

  /**
   * Validates and sanitizes a numeric input, converting strings to numbers.
   * Clamps the number to `min`/`max` if provided.
   * @param input - The number or string to validate and sanitize.
   * @param min - Minimum allowed value (inclusive).
   * @param max - Maximum allowed value (inclusive).
   * @returns The sanitized (and potentially clamped) number.
   * @throws {McpError} If input is not a valid number, NaN, or Infinity.
   */
  public sanitizeNumber(
    input: number | string,
    min?: number,
    max?: number,
  ): number {
    let value: number;
    if (typeof input === "string") {
      const trimmedInput = input.trim();
      if (trimmedInput === "" || !validator.isNumeric(trimmedInput)) {
        throw new McpError(
          BaseErrorCode.VALIDATION_ERROR,
          "Invalid number format: input is empty or not numeric.",
          { input },
        );
      }
      value = parseFloat(trimmedInput);
    } else if (typeof input === "number") {
      value = input;
    } else {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        "Invalid input type: expected number or string.",
        { input: String(input) },
      );
    }

    if (isNaN(value) || !isFinite(value)) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        "Invalid number value (NaN or Infinity).",
        { input },
      );
    }

    let clamped = false;
    let originalValueForLog = value;
    if (min !== undefined && value < min) {
      value = min;
      clamped = true;
    }
    if (max !== undefined && value > max) {
      value = max;
      clamped = true;
    }
    if (clamped) {
      logger.debug(
        "Number clamped to range.",
        requestContextService.createRequestContext({
          operation: "Sanitization.sanitizeNumber.clamped",
          originalInput: String(input),
          parsedValue: originalValueForLog,
          minValue: min,
          maxValue: max,
          clampedValue: value,
        }),
      );
    }
    return value;
  }

  /**
   * Sanitizes input for logging by redacting sensitive fields.
   * Creates a deep clone and replaces values of fields matching `this.sensitiveFields`
   * (case-insensitive substring match) with "[REDACTED]".
   * @param input - The input data to sanitize for logging.
   * @returns A sanitized (deep cloned) version of the input, safe for logging.
   *   Returns original input if not object/array, or "[Log Sanitization Failed]" on error.
   */
  public sanitizeForLogging(input: unknown): unknown {
    try {
      if (!input || typeof input !== "object") return input;

      const clonedInput =
        typeof structuredClone === "function"
          ? structuredClone(input)
          : JSON.parse(JSON.stringify(input));
      this.redactSensitiveFields(clonedInput);
      return clonedInput;
    } catch (error) {
      logger.error(
        "Error during log sanitization, returning placeholder.",
        requestContextService.createRequestContext({
          operation: "Sanitization.sanitizeForLogging.error",
          errorMessage: error instanceof Error ? error.message : String(error),
        }),
      );
      return "[Log Sanitization Failed]";
    }
  }

  /**
   * Recursively redacts sensitive fields in an object or array in place.
   * @param obj - The object or array to redact.
   * @private
   */
  private redactSensitiveFields(obj: unknown): void {
    if (!obj || typeof obj !== "object") return;

    if (Array.isArray(obj)) {
      obj.forEach((item) => this.redactSensitiveFields(item));
      return;
    }

    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        const value = (obj as Record<string, unknown>)[key];
        const lowerKey = key.toLowerCase();
        const isSensitive = this.sensitiveFields.some((field) =>
          lowerKey.includes(field),
        );

        if (isSensitive) {
          (obj as Record<string, unknown>)[key] = "[REDACTED]";
        } else if (value && typeof value === "object") {
          this.redactSensitiveFields(value);
        }
      }
    }
  }
}

/**
 * Singleton instance of the `Sanitization` class.
 * Use this for all input sanitization tasks.
 */
export const sanitization = Sanitization.getInstance();

/**
 * Convenience function calling `sanitization.sanitizeForLogging`.
 * @param input - The input data to sanitize.
 * @returns A sanitized version of the input, safe for logging.
 */
export const sanitizeInputForLogging = (input: unknown): unknown =>
  sanitization.sanitizeForLogging(input);

```

--------------------------------------------------------------------------------
/src/mcp-server/transports/httpTransport.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Handles the setup and management of the Streamable HTTP MCP transport.
 * Implements the MCP Specification 2025-03-26 for Streamable HTTP.
 * This includes creating an Express server, configuring middleware (CORS, Authentication),
 * defining request routing for the single MCP endpoint (POST/GET/DELETE),
 * managing server-side sessions, handling Server-Sent Events (SSE) for streaming,
 * and binding to a network port with retry logic for port conflicts.
 *
 * Specification Reference:
 * https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#streamable-http
 * @module src/mcp-server/transports/httpTransport
 */

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
import express, { NextFunction, Request, Response } from "express";
import http from "http";
import { randomUUID } from "node:crypto";
import { config } from "../../config/index.js";
import {
  logger,
  requestContextService,
} from "../../utils/internal/index.js"; // Corrected path
import { RequestContext } from "../../utils/internal/requestContext.js"; // Explicit path for RequestContext
import { mcpAuthMiddleware } from "./authentication/authMiddleware.js";

/**
 * The port number for the HTTP transport, configured via `MCP_HTTP_PORT` environment variable.
 * Defaults to 3010 if not specified (default is managed by the config module).
 * @constant {number} HTTP_PORT
 * @private
 */
const HTTP_PORT = config.mcpHttpPort;

/**
 * The host address for the HTTP transport, configured via `MCP_HTTP_HOST` environment variable.
 * Defaults to '127.0.0.1' if not specified (default is managed by the config module).
 * MCP Spec Security Note: Recommends binding to localhost for local servers to minimize exposure.
 * @private
 */
const HTTP_HOST = config.mcpHttpHost;

/**
 * The single HTTP endpoint path for all MCP communication, as required by the MCP specification.
 * This endpoint supports POST, GET, DELETE, and OPTIONS methods.
 * @constant {string} MCP_ENDPOINT_PATH
 * @private
 */
const MCP_ENDPOINT_PATH = "/mcp";

/**
 * Maximum number of attempts to find an available port if the initial `HTTP_PORT` is in use.
 * The server will try ports sequentially: `HTTP_PORT`, `HTTP_PORT + 1`, ..., up to `MAX_PORT_RETRIES`.
 * @constant {number} MAX_PORT_RETRIES
 * @private
 */
const MAX_PORT_RETRIES = 15;

/**
 * Stores active `StreamableHTTPServerTransport` instances from the SDK, keyed by their session ID.
 * This is essential for routing subsequent HTTP requests (GET, DELETE, non-initialize POST)
 * to the correct stateful session transport instance.
 * @type {Record<string, StreamableHTTPServerTransport>}
 * @private
 */
const httpTransports: Record<string, StreamableHTTPServerTransport> = {};

/**
 * Checks if an incoming HTTP request's `Origin` header is permissible based on configuration.
 * MCP Spec Security: Servers MUST validate the `Origin` header for cross-origin requests.
 * This function checks the request's origin against the `config.mcpAllowedOrigins` list.
 * If the server is bound to localhost, requests from localhost or with no/null origin are also permitted.
 * Sets appropriate CORS headers (`Access-Control-Allow-Origin`, etc.) if the origin is allowed.
 *
 * @param req - The Express request object.
 * @param res - The Express response object.
 * @returns True if the origin is allowed, false otherwise.
 * @private
 */
function isOriginAllowed(req: Request, res: Response): boolean {
  const origin = req.headers.origin;
  const host = req.hostname;
  const isLocalhostBinding = ["127.0.0.1", "::1", "localhost"].includes(host);
  const allowedOrigins = config.mcpAllowedOrigins || [];
  const context = requestContextService.createRequestContext({
    operation: "isOriginAllowed",
    origin,
    host,
    isLocalhostBinding,
    allowedOrigins,
  });
  logger.debug("Checking origin allowance", context);

  const allowed =
    (origin && allowedOrigins.includes(origin)) ||
    (isLocalhostBinding && (!origin || origin === "null"));

  if (allowed && origin) {
    res.setHeader("Access-Control-Allow-Origin", origin);
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
    res.setHeader(
      "Access-Control-Allow-Headers",
      "Content-Type, Mcp-Session-Id, Last-Event-ID, Authorization",
    );
    res.setHeader("Access-Control-Allow-Credentials", "true");
  } else if (!allowed && origin) {
    logger.warning(`Origin denied: ${origin}`, context);
  }
  logger.debug(`Origin check result: ${allowed}`, { ...context, allowed });
  return allowed;
}

/**
 * Proactively checks if a specific network port is already in use.
 * @param port - The port number to check.
 * @param host - The host address to check the port on.
 * @param parentContext - Logging context from the caller.
 * @returns A promise that resolves to `true` if the port is in use, or `false` otherwise.
 * @private
 */
async function isPortInUse(
  port: number,
  host: string,
  parentContext: RequestContext,
): Promise<boolean> {
  const checkContext = requestContextService.createRequestContext({
    ...parentContext,
    operation: "isPortInUse",
    port,
    host,
  });
  logger.debug(`Proactively checking port usability...`, checkContext);
  return new Promise((resolve) => {
    const tempServer = http.createServer();
    tempServer
      .once("error", (err: NodeJS.ErrnoException) => {
        if (err.code === "EADDRINUSE") {
          logger.debug(
            `Proactive check: Port confirmed in use (EADDRINUSE).`,
            checkContext,
          );
          resolve(true);
        } else {
          logger.debug(
            `Proactive check: Non-EADDRINUSE error encountered: ${err.message}`,
            { ...checkContext, errorCode: err.code },
          );
          resolve(false);
        }
      })
      .once("listening", () => {
        logger.debug(`Proactive check: Port is available.`, checkContext);
        tempServer.close(() => resolve(false));
      })
      .listen(port, host);
  });
}

/**
 * Attempts to start the HTTP server, retrying on incrementing ports if `EADDRINUSE` occurs.
 *
 * @param serverInstance - The Node.js HTTP server instance.
 * @param initialPort - The initial port number to try.
 * @param host - The host address to bind to.
 * @param maxRetries - Maximum number of additional ports to attempt.
 * @param parentContext - Logging context from the caller.
 * @returns A promise that resolves with the port number the server successfully bound to.
 * @throws {Error} If binding fails after all retries or for a non-EADDRINUSE error.
 * @private
 */
function startHttpServerWithRetry(
  serverInstance: http.Server,
  initialPort: number,
  host: string,
  maxRetries: number,
  parentContext: RequestContext,
): Promise<number> {
  const startContext = requestContextService.createRequestContext({
    ...parentContext,
    operation: "startHttpServerWithRetry",
    initialPort,
    host,
    maxRetries,
  });
  logger.debug(`Attempting to start HTTP server...`, startContext);
  return new Promise(async (resolve, reject) => {
    let lastError: Error | null = null;
    for (let i = 0; i <= maxRetries; i++) {
      const currentPort = initialPort + i;
      const attemptContext = requestContextService.createRequestContext({
        ...startContext,
        port: currentPort,
        attempt: i + 1,
        maxAttempts: maxRetries + 1,
      });
      logger.debug(
        `Attempting port ${currentPort} (${attemptContext.attempt}/${attemptContext.maxAttempts})`,
        attemptContext,
      );

      if (await isPortInUse(currentPort, host, attemptContext)) {
        logger.warning(
          `Proactive check detected port ${currentPort} is in use, retrying...`,
          attemptContext,
        );
        lastError = new Error(
          `EADDRINUSE: Port ${currentPort} detected as in use by proactive check.`,
        );
        await new Promise((res) => setTimeout(res, 100));
        continue;
      }

      try {
        await new Promise<void>((listenResolve, listenReject) => {
          serverInstance
            .listen(currentPort, host, () => {
              const serverAddress = `http://${host}:${currentPort}${MCP_ENDPOINT_PATH}`;
              logger.info(
                `HTTP transport successfully listening on host ${host} at ${serverAddress}`,
                { ...attemptContext, address: serverAddress },
              );
              listenResolve();
            })
            .on("error", (err: NodeJS.ErrnoException) => {
              listenReject(err);
            });
        });
        resolve(currentPort);
        return;
      } catch (err: any) {
        lastError = err;
        logger.debug(
          `Listen error on port ${currentPort}: Code=${err.code}, Message=${err.message}`,
          { ...attemptContext, errorCode: err.code, errorMessage: err.message },
        );
        if (err.code === "EADDRINUSE") {
          logger.warning(
            `Port ${currentPort} already in use (EADDRINUSE), retrying...`,
            attemptContext,
          );
          await new Promise((res) => setTimeout(res, 100));
        } else {
          logger.error(
            `Failed to bind to port ${currentPort} due to non-EADDRINUSE error: ${err.message}`,
            { ...attemptContext, error: err.message },
          );
          reject(err);
          return;
        }
      }
    }
    logger.error(
      `Failed to bind to any port after ${maxRetries + 1} attempts. Last error: ${lastError?.message}`,
      { ...startContext, error: lastError?.message },
    );
    reject(
      lastError ||
        new Error("Failed to bind to any port after multiple retries."),
    );
  });
}

/**
 * Sets up and starts the Streamable HTTP transport layer for the MCP server.
 *
 * @param createServerInstanceFn - An asynchronous factory function that returns a new `McpServer` instance.
 * @param parentContext - Logging context from the main server startup process.
 * @returns A promise that resolves when the HTTP server is successfully listening.
 * @throws {Error} If the server fails to start after all port retries.
 */
export async function startHttpTransport(
  createServerInstanceFn: () => Promise<McpServer>,
  parentContext: RequestContext,
): Promise<void> {
  const app = express();
  const transportContext = requestContextService.createRequestContext({
    ...parentContext,
    transportType: "HTTP",
    component: "HttpTransportSetup",
  });
  logger.debug(
    "Setting up Express app for HTTP transport...",
    transportContext,
  );

  app.use(express.json());

  app.options(MCP_ENDPOINT_PATH, (req, res) => {
    const optionsContext = requestContextService.createRequestContext({
      ...transportContext,
      operation: "handleOptions",
      origin: req.headers.origin,
      method: req.method,
      path: req.path,
    });
    logger.debug(
      `Received OPTIONS request for ${MCP_ENDPOINT_PATH}`,
      optionsContext,
    );
    if (isOriginAllowed(req, res)) {
      logger.debug(
        "OPTIONS request origin allowed, sending 204.",
        optionsContext,
      );
      res.sendStatus(204);
    } else {
      logger.debug(
        "OPTIONS request origin denied, sending 403.",
        optionsContext,
      );
      res.status(403).send("Forbidden: Invalid Origin");
    }
  });

  app.use((req: Request, res: Response, next: NextFunction) => {
    const securityContext = requestContextService.createRequestContext({
      ...transportContext,
      operation: "securityMiddleware",
      path: req.path,
      method: req.method,
      origin: req.headers.origin,
    });
    logger.debug(`Applying security middleware...`, securityContext);
    if (!isOriginAllowed(req, res)) {
      logger.debug("Origin check failed, sending 403.", securityContext);
      res.status(403).send("Forbidden: Invalid Origin");
      return;
    }
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
    res.setHeader(
      "Content-Security-Policy",
      "default-src 'self'; script-src 'self'; object-src 'none'; style-src 'self'; img-src 'self'; media-src 'self'; frame-src 'none'; font-src 'self'; connect-src 'self'",
    );
    logger.debug("Security middleware passed.", securityContext);
    next();
  });

  app.use(mcpAuthMiddleware);

  app.post(MCP_ENDPOINT_PATH, async (req, res) => {
    const basePostContext = requestContextService.createRequestContext({
      ...transportContext,
      operation: "handlePost",
      method: "POST",
      path: req.path,
      origin: req.headers.origin,
    });
    logger.debug(`Received POST request on ${MCP_ENDPOINT_PATH}`, {
      ...basePostContext,
      headers: req.headers,
      bodyPreview: JSON.stringify(req.body).substring(0, 100),
    });

    const sessionId = req.headers["mcp-session-id"] as string | undefined;
    logger.debug(`Extracted session ID: ${sessionId}`, {
      ...basePostContext,
      sessionId,
    });

    let transport = sessionId ? httpTransports[sessionId] : undefined;
    logger.debug(`Found existing transport for session ID: ${!!transport}`, {
      ...basePostContext,
      sessionId,
    });

    const isInitReq = isInitializeRequest(req.body);
    logger.debug(`Is InitializeRequest: ${isInitReq}`, {
      ...basePostContext,
      sessionId,
    });
    const requestId = (req.body as any)?.id || null;

    try {
      if (isInitReq) {
        if (transport) {
          logger.warning(
            "Received InitializeRequest on an existing session ID. Closing old session and creating new.",
            { ...basePostContext, sessionId },
          );
          await transport.close();
          delete httpTransports[sessionId!];
        }
        logger.info("Handling Initialize Request: Creating new session...", {
          ...basePostContext,
          sessionId,
        });

        transport = new StreamableHTTPServerTransport({
          sessionIdGenerator: () => {
            const newId = randomUUID();
            logger.debug(`Generated new session ID: ${newId}`, basePostContext);
            return newId;
          },
          onsessioninitialized: (newId) => {
            logger.debug(
              `Session initialized callback triggered for ID: ${newId}`,
              { ...basePostContext, newSessionId: newId },
            );
            httpTransports[newId] = transport!;
            logger.info(`HTTP Session created: ${newId}`, {
              ...basePostContext,
              newSessionId: newId,
            });
          },
        });

        transport.onclose = () => {
          const closedSessionId = transport!.sessionId;
          if (closedSessionId) {
            logger.debug(
              `onclose handler triggered for session ID: ${closedSessionId}`,
              { ...basePostContext, closedSessionId },
            );
            delete httpTransports[closedSessionId];
            logger.info(`HTTP Session closed: ${closedSessionId}`, {
              ...basePostContext,
              closedSessionId,
            });
          } else {
            logger.debug(
              "onclose handler triggered for transport without session ID (likely init failure).",
              basePostContext,
            );
          }
        };

        logger.debug(
          "Creating McpServer instance for new session...",
          basePostContext,
        );
        const server = await createServerInstanceFn();
        logger.debug(
          "Connecting McpServer to new transport...",
          basePostContext,
        );
        await server.connect(transport);
        logger.debug("McpServer connected to transport.", basePostContext);
      } else if (!transport) {
        logger.warning(
          "Invalid or missing session ID for non-initialize POST request.",
          { ...basePostContext, sessionId },
        );
        res.status(404).json({
          jsonrpc: "2.0",
          error: { code: -32004, message: "Invalid or expired session ID" },
          id: requestId,
        });
        return;
      }

      const currentSessionId = transport.sessionId;
      logger.debug(
        `Processing POST request content for session ${currentSessionId}...`,
        { ...basePostContext, sessionId: currentSessionId, isInitReq },
      );
      await transport.handleRequest(req, res, req.body);
      logger.debug(
        `Finished processing POST request content for session ${currentSessionId}.`,
        { ...basePostContext, sessionId: currentSessionId },
      );
    } catch (err) {
      const errorSessionId = transport?.sessionId || sessionId;
      logger.error("Error handling POST request", {
        ...basePostContext,
        sessionId: errorSessionId,
        isInitReq,
        error: err instanceof Error ? err.message : String(err),
        stack: err instanceof Error ? err.stack : undefined,
      });
      if (!res.headersSent) {
        res.status(500).json({
          jsonrpc: "2.0",
          error: {
            code: -32603,
            message: "Internal server error during POST handling",
          },
          id: requestId,
        });
      }
      if (isInitReq && transport && !transport.sessionId) {
        logger.debug("Cleaning up transport after initialization failure.", {
          ...basePostContext,
          sessionId: errorSessionId,
        });
        await transport.close().catch((closeErr) =>
          logger.error("Error closing transport after init failure", {
            ...basePostContext,
            sessionId: errorSessionId,
            closeError: closeErr,
          }),
        );
      }
    }
  });

  const handleSessionReq = async (req: Request, res: Response) => {
    const method = req.method;
    const baseSessionReqContext = requestContextService.createRequestContext({
      ...transportContext,
      operation: `handle${method}`,
      method,
      path: req.path,
      origin: req.headers.origin,
    });
    logger.debug(`Received ${method} request on ${MCP_ENDPOINT_PATH}`, {
      ...baseSessionReqContext,
      headers: req.headers,
    });

    const sessionId = req.headers["mcp-session-id"] as string | undefined;
    logger.debug(`Extracted session ID: ${sessionId}`, {
      ...baseSessionReqContext,
      sessionId,
    });

    const transport = sessionId ? httpTransports[sessionId] : undefined;
    logger.debug(`Found existing transport for session ID: ${!!transport}`, {
      ...baseSessionReqContext,
      sessionId,
    });

    if (!transport) {
      logger.warning(`Session not found for ${method} request`, {
        ...baseSessionReqContext,
        sessionId,
      });
      res.status(404).json({
        jsonrpc: "2.0",
        error: { code: -32004, message: "Session not found or expired" },
        id: null, // Or a relevant request identifier if available from context
      });
      return;
    }

    try {
      logger.debug(
        `Delegating ${method} request to transport for session ${sessionId}...`,
        { ...baseSessionReqContext, sessionId },
      );
      await transport.handleRequest(req, res);
      logger.info(
        `Successfully handled ${method} request for session ${sessionId}`,
        { ...baseSessionReqContext, sessionId },
      );
    } catch (err) {
      logger.error(
        `Error handling ${method} request for session ${sessionId}`,
        {
          ...baseSessionReqContext,
          sessionId,
          error: err instanceof Error ? err.message : String(err),
          stack: err instanceof Error ? err.stack : undefined,
        },
      );
      if (!res.headersSent) {
        res.status(500).json({
          jsonrpc: "2.0",
          error: { code: -32603, message: "Internal Server Error" },
          id: null, // Or a relevant request identifier
        });
      }
    }
  };
  app.get(MCP_ENDPOINT_PATH, handleSessionReq);
  app.delete(MCP_ENDPOINT_PATH, handleSessionReq);

  logger.debug("Creating HTTP server instance...", transportContext);
  const serverInstance = http.createServer(app);
  try {
    logger.debug(
      "Attempting to start HTTP server with retry logic...",
      transportContext,
    );
    const actualPort = await startHttpServerWithRetry(
      serverInstance,
      config.mcpHttpPort,
      config.mcpHttpHost,
      MAX_PORT_RETRIES,
      transportContext,
    );

    let serverAddressLog = `http://${config.mcpHttpHost}:${actualPort}${MCP_ENDPOINT_PATH}`;
    let productionNote = "";
    if (config.environment === "production") {
      // The server itself runs HTTP, but it's expected to be behind an HTTPS proxy in production.
      // The log reflects the effective public-facing URL.
      serverAddressLog = `https://${config.mcpHttpHost}:${actualPort}${MCP_ENDPOINT_PATH}`;
      productionNote = ` (via HTTPS, ensure reverse proxy is configured)`;
    }

    if (process.stdout.isTTY) {
      console.log(
        `\n🚀 MCP Server running in HTTP mode at: ${serverAddressLog}${productionNote}\n   (MCP Spec: 2025-03-26 Streamable HTTP Transport)\n`,
      );
    }
  } catch (err) {
    logger.fatal("HTTP server failed to start after multiple port retries.", {
      ...transportContext,
      error: err instanceof Error ? err.message : String(err),
    });
    throw err;
  }
}

```
Page 2/2FirstPrevNextLast