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

# Directory Structure

```
├── .clinerules
├── .dockerignore
├── .env.example
├── .github
│   ├── FUNDING.yml
│   └── workflows
│       └── publish.yml
├── .gitignore
├── .ncurc.json
├── .repomixignore
├── automated-tests
│   └── AGENT_TEST_05282025.md
├── CHANGELOG.md
├── CLAUDE.md
├── docker-compose.yml
├── docs
│   └── tree.md
├── examples
│   ├── backup-example
│   │   ├── knowledges.json
│   │   ├── projects.json
│   │   ├── relationships.json
│   │   └── tasks.json
│   ├── deep-research-example
│   │   ├── covington_community_grant_research.md
│   │   └── full-export.json
│   ├── README.md
│   └── webui-example.png
├── LICENSE
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── repomix.config.json
├── scripts
│   ├── clean.ts
│   ├── fetch-openapi-spec.ts
│   ├── make-executable.ts
│   └── tree.ts
├── smithery.yaml
├── src
│   ├── config
│   │   └── index.ts
│   ├── index.ts
│   ├── mcp
│   │   ├── resources
│   │   │   ├── index.ts
│   │   │   ├── knowledge
│   │   │   │   └── knowledgeResources.ts
│   │   │   ├── projects
│   │   │   │   └── projectResources.ts
│   │   │   ├── tasks
│   │   │   │   └── taskResources.ts
│   │   │   └── types.ts
│   │   ├── server.ts
│   │   ├── tools
│   │   │   ├── atlas_database_clean
│   │   │   │   ├── cleanDatabase.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_deep_research
│   │   │   │   ├── deepResearch.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_knowledge_add
│   │   │   │   ├── addKnowledge.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_knowledge_delete
│   │   │   │   ├── deleteKnowledge.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_knowledge_list
│   │   │   │   ├── index.ts
│   │   │   │   ├── listKnowledge.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_project_create
│   │   │   │   ├── createProject.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_project_delete
│   │   │   │   ├── deleteProject.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_project_list
│   │   │   │   ├── index.ts
│   │   │   │   ├── listProjects.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_project_update
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── updateProject.ts
│   │   │   ├── atlas_task_create
│   │   │   │   ├── createTask.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_task_delete
│   │   │   │   ├── deleteTask.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_task_list
│   │   │   │   ├── index.ts
│   │   │   │   ├── listTasks.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   └── types.ts
│   │   │   ├── atlas_task_update
│   │   │   │   ├── index.ts
│   │   │   │   ├── responseFormat.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── updateTask.ts
│   │   │   └── atlas_unified_search
│   │   │       ├── index.ts
│   │   │       ├── responseFormat.ts
│   │   │       ├── types.ts
│   │   │       └── unifiedSearch.ts
│   │   └── transports
│   │       ├── authentication
│   │       │   └── authMiddleware.ts
│   │       ├── httpTransport.ts
│   │       └── stdioTransport.ts
│   ├── services
│   │   └── neo4j
│   │       ├── backupRestoreService
│   │       │   ├── backupRestoreTypes.ts
│   │       │   ├── backupUtils.ts
│   │       │   ├── exportLogic.ts
│   │       │   ├── importLogic.ts
│   │       │   ├── index.ts
│   │       │   └── scripts
│   │       │       ├── db-backup.ts
│   │       │       └── db-import.ts
│   │       ├── driver.ts
│   │       ├── events.ts
│   │       ├── helpers.ts
│   │       ├── index.ts
│   │       ├── knowledgeService.ts
│   │       ├── projectService.ts
│   │       ├── searchService
│   │       │   ├── fullTextSearchLogic.ts
│   │       │   ├── index.ts
│   │       │   ├── searchTypes.ts
│   │       │   └── unifiedSearchLogic.ts
│   │       ├── taskService.ts
│   │       ├── types.ts
│   │       └── utils.ts
│   ├── types
│   │   ├── 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
│   └── webui
│       ├── index.html
│       ├── logic
│       │   ├── api-service.js
│       │   ├── app-state.js
│       │   ├── config.js
│       │   ├── dom-elements.js
│       │   ├── main.js
│       │   └── ui-service.js
│       └── styling
│           ├── base.css
│           ├── components.css
│           ├── layout.css
│           └── theme.css
├── tsconfig.json
├── tsconfig.typedoc.json
└── typedoc.json
```

# Files

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_delete/deleteProject.ts:
--------------------------------------------------------------------------------

```typescript
import { ProjectService } from "../../../services/neo4j/projectService.js";
import {
  BaseErrorCode,
  McpError,
  ProjectErrorCode,
} from "../../../types/errors.js";
import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { ToolContext } from "../../../types/tool.js";
import { AtlasProjectDeleteInput, AtlasProjectDeleteSchema } from "./types.js";
import { formatProjectDeleteResponse } from "./responseFormat.js";

export const atlasDeleteProject = async (
  input: unknown,
  context: ToolContext,
) => {
  let validatedInput: AtlasProjectDeleteInput | undefined;
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasDeleteProject",
    });

  try {
    // Parse and validate input against schema definition
    validatedInput = AtlasProjectDeleteSchema.parse(input);

    // Select operation strategy based on request mode
    if (validatedInput.mode === "bulk") {
      // Process bulk removal operation
      const { projectIds } = validatedInput;

      logger.info("Initiating batch project removal", {
        ...reqContext,
        count: projectIds.length,
        projectIds,
      });

      const results = {
        success: true,
        message: `Successfully removed ${projectIds.length} projects`,
        deleted: [] as string[],
        errors: [] as {
          projectId: string;
          error: {
            code: string;
            message: string;
            details?: any;
          };
        }[],
      };

      // Process removal operations sequentially to maintain data integrity
      for (const projectId of projectIds) {
        try {
          const deleted = await ProjectService.deleteProject(projectId);

          if (deleted) {
            results.deleted.push(projectId);
          } else {
            // Project not found
            results.success = false;
            results.errors.push({
              projectId,
              error: {
                code: ProjectErrorCode.PROJECT_NOT_FOUND,
                message: `Project with ID ${projectId} not found`,
              },
            });
          }
        } catch (error) {
          results.success = false;
          results.errors.push({
            projectId,
            error: {
              code:
                error instanceof McpError
                  ? error.code
                  : BaseErrorCode.INTERNAL_ERROR,
              message: error instanceof Error ? error.message : "Unknown error",
              details: error instanceof McpError ? error.details : undefined,
            },
          });
        }
      }

      if (results.errors.length > 0) {
        results.message = `Removed ${results.deleted.length} of ${projectIds.length} projects with ${results.errors.length} errors`;
      }

      logger.info("Batch removal operation completed", {
        ...reqContext,
        successCount: results.deleted.length,
        errorCount: results.errors.length,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(results, null, 2));
      } else {
        return formatProjectDeleteResponse(results);
      }
    } else {
      // Process single entity removal
      const { id } = validatedInput;

      logger.info("Removing project entity", {
        ...reqContext,
        projectId: id,
      });

      const deleted = await ProjectService.deleteProject(id);

      if (!deleted) {
        logger.warning("Target project not found for removal operation", {
          ...reqContext,
          projectId: id,
        });

        throw new McpError(
          ProjectErrorCode.PROJECT_NOT_FOUND,
          `Project with identifier ${id} not found`,
          { projectId: id },
        );
      }

      logger.info("Project successfully removed", {
        ...reqContext,
        projectId: id,
      });

      const result = {
        id,
        success: true,
        message: `Project with ID ${id} removed successfully`,
      };

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(result, null, 2));
      } else {
        return formatProjectDeleteResponse(result);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

    logger.error("Project removal operation failed", error as Error, {
      ...reqContext,
      inputReceived: validatedInput ?? input,
    });

    // Translate unknown errors to structured McpError format
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Failed to remove project(s): ${error instanceof Error ? error.message : "Unknown error"}`,
    );
  }
};

```

--------------------------------------------------------------------------------
/src/utils/metrics/tokenCounter.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides utility functions for counting tokens in text and chat messages
 * using the `tiktoken` library, specifically configured for 'gpt-4o' tokenization.
 * These functions are essential for managing token limits and estimating costs
 * when interacting with language models.
 * @module src/utils/metrics/tokenCounter
 */
import { ChatCompletionMessageParam } from "openai/resources/chat/completions";
import { encoding_for_model, Tiktoken, TiktokenModel } from "tiktoken";
import { BaseErrorCode, McpError } from "../../types/errors.js";
import { ErrorHandler, logger, RequestContext } from "../index.js";

/**
 * The specific Tiktoken model used for all tokenization operations in this module.
 * This ensures consistent token counting.
 * @private
 */
const TOKENIZATION_MODEL: TiktokenModel = "gpt-4o";

/**
 * Calculates the number of tokens for a given text string using the
 * tokenizer specified by `TOKENIZATION_MODEL`.
 * Wraps tokenization in `ErrorHandler.tryCatch` for robust error management.
 *
 * @param text - The input text to tokenize.
 * @param context - Optional request context for logging and error handling.
 * @returns A promise that resolves with the number of tokens in the text.
 * @throws {McpError} If tokenization fails.
 */
export async function countTokens(
  text: string,
  context?: RequestContext,
): Promise<number> {
  return ErrorHandler.tryCatch(
    () => {
      let encoding: Tiktoken | null = null;
      try {
        encoding = encoding_for_model(TOKENIZATION_MODEL);
        const tokens = encoding.encode(text);
        return tokens.length;
      } finally {
        encoding?.free();
      }
    },
    {
      operation: "countTokens",
      context: context,
      input: { textSample: text.substring(0, 50) + "..." },
      errorCode: BaseErrorCode.INTERNAL_ERROR,
    },
  );
}

/**
 * Calculates the estimated number of tokens for an array of chat messages.
 * Uses the tokenizer specified by `TOKENIZATION_MODEL` and accounts for
 * special tokens and message overhead according to OpenAI's guidelines.
 *
 * For multi-part content, only text parts are currently tokenized.
 *
 * Reference: {@link https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb}
 *
 * @param messages - An array of chat messages.
 * @param context - Optional request context for logging and error handling.
 * @returns A promise that resolves with the estimated total number of tokens.
 * @throws {McpError} If tokenization fails.
 */
export async function countChatTokens(
  messages: ReadonlyArray<ChatCompletionMessageParam>,
  context?: RequestContext,
): Promise<number> {
  return ErrorHandler.tryCatch(
    () => {
      let encoding: Tiktoken | null = null;
      let num_tokens = 0;
      try {
        encoding = encoding_for_model(TOKENIZATION_MODEL);

        const tokens_per_message = 3; // For gpt-4o, gpt-4, gpt-3.5-turbo
        const tokens_per_name = 1; // For gpt-4o, gpt-4, gpt-3.5-turbo

        for (const message of messages) {
          num_tokens += tokens_per_message;
          num_tokens += encoding.encode(message.role).length;

          if (typeof message.content === "string") {
            num_tokens += encoding.encode(message.content).length;
          } else if (Array.isArray(message.content)) {
            for (const part of message.content) {
              if (part.type === "text") {
                num_tokens += encoding.encode(part.text).length;
              } else {
                logger.warning(
                  `Non-text content part found (type: ${part.type}), token count contribution ignored.`,
                  context,
                );
              }
            }
          }

          if ("name" in message && message.name) {
            num_tokens += tokens_per_name;
            num_tokens += encoding.encode(message.name).length;
          }

          if (
            message.role === "assistant" &&
            "tool_calls" in message &&
            message.tool_calls
          ) {
            for (const tool_call of message.tool_calls) {
              if (tool_call.function.name) {
                num_tokens += encoding.encode(tool_call.function.name).length;
              }
              if (tool_call.function.arguments) {
                num_tokens += encoding.encode(
                  tool_call.function.arguments,
                ).length;
              }
            }
          }

          if (
            message.role === "tool" &&
            "tool_call_id" in message &&
            message.tool_call_id
          ) {
            num_tokens += encoding.encode(message.tool_call_id).length;
          }
        }
        num_tokens += 3; // Every reply is primed with <|start|>assistant<|message|>
        return num_tokens;
      } finally {
        encoding?.free();
      }
    },
    {
      operation: "countChatTokens",
      context: context,
      input: { messageCount: messages.length },
      errorCode: BaseErrorCode.INTERNAL_ERROR,
    },
  );
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_delete/deleteKnowledge.ts:
--------------------------------------------------------------------------------

```typescript
import { KnowledgeService } from "../../../services/neo4j/knowledgeService.js";
import { BaseErrorCode, McpError } from "../../../types/errors.js";
import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { ToolContext } from "../../../types/tool.js";
import {
  AtlasKnowledgeDeleteInput,
  AtlasKnowledgeDeleteSchema,
} from "./types.js";
import { formatKnowledgeDeleteResponse } from "./responseFormat.js";

export const atlasDeleteKnowledge = async (
  input: unknown,
  context: ToolContext,
) => {
  let validatedInput: AtlasKnowledgeDeleteInput | undefined;
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasDeleteKnowledge",
    });

  try {
    // Parse and validate input against schema definition
    validatedInput = AtlasKnowledgeDeleteSchema.parse(input);

    // Select operation strategy based on request mode
    if (validatedInput.mode === "bulk") {
      // Process bulk removal operation
      const { knowledgeIds } = validatedInput;

      logger.info("Initiating batch knowledge item removal", {
        ...reqContext,
        count: knowledgeIds.length,
        knowledgeIds,
      });

      const results = {
        success: true,
        message: `Successfully removed ${knowledgeIds.length} knowledge items`,
        deleted: [] as string[],
        errors: [] as {
          knowledgeId: string;
          error: {
            code: string;
            message: string;
            details?: any;
          };
        }[],
      };

      // Process removal operations sequentially to maintain data integrity
      for (const knowledgeId of knowledgeIds) {
        try {
          const deleted = await KnowledgeService.deleteKnowledge(knowledgeId);

          if (deleted) {
            results.deleted.push(knowledgeId);
          } else {
            // Knowledge item not found
            results.success = false;
            results.errors.push({
              knowledgeId,
              error: {
                code: BaseErrorCode.NOT_FOUND,
                message: `Knowledge item with ID ${knowledgeId} not found`,
              },
            });
          }
        } catch (error) {
          results.success = false;
          results.errors.push({
            knowledgeId,
            error: {
              code:
                error instanceof McpError
                  ? error.code
                  : BaseErrorCode.INTERNAL_ERROR,
              message: error instanceof Error ? error.message : "Unknown error",
              details: error instanceof McpError ? error.details : undefined,
            },
          });
        }
      }

      if (results.errors.length > 0) {
        results.message = `Removed ${results.deleted.length} of ${knowledgeIds.length} knowledge items with ${results.errors.length} errors`;
      }

      logger.info("Batch knowledge removal operation completed", {
        ...reqContext,
        successCount: results.deleted.length,
        errorCount: results.errors.length,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(results, null, 2));
      } else {
        return formatKnowledgeDeleteResponse(results);
      }
    } else {
      // Process single entity removal
      const { id } = validatedInput;

      logger.info("Removing knowledge item", {
        ...reqContext,
        knowledgeId: id,
      });

      const deleted = await KnowledgeService.deleteKnowledge(id);

      if (!deleted) {
        logger.warning(
          "Target knowledge item not found for removal operation",
          {
            ...reqContext,
            knowledgeId: id,
          },
        );

        throw new McpError(
          BaseErrorCode.NOT_FOUND,
          `Knowledge item with identifier ${id} not found`,
          { knowledgeId: id },
        );
      }

      logger.info("Knowledge item successfully removed", {
        ...reqContext,
        knowledgeId: id,
      });

      const result = {
        id,
        success: true,
        message: `Knowledge item with ID ${id} removed successfully`,
      };

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(result, null, 2));
      } else {
        return formatKnowledgeDeleteResponse(result);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

    logger.error("Knowledge item removal operation failed", error as Error, {
      ...reqContext,
      inputReceived: validatedInput ?? input,
    });

    // Translate unknown errors to structured McpError format
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Failed to remove knowledge item(s): ${error instanceof Error ? error.message : "Unknown error"}`,
    );
  }
};

```

--------------------------------------------------------------------------------
/src/utils/parsing/dateParser.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides utility functions for parsing natural language date strings
 * into Date objects or detailed parsing results using the `chrono-node` library.
 * @module src/utils/parsing/dateParser
 */
import * as chrono from "chrono-node";
import { BaseErrorCode, McpError } from "../../types/errors.js";
import { ErrorHandler, logger, RequestContext } from "../index.js";

/**
 * Parses a natural language date string into a JavaScript Date object.
 * Uses `chrono.parseDate` for lenient parsing of various date formats.
 *
 * @param text - The natural language date string to parse.
 * @param context - The request context for logging and error tracking.
 * @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
 * @returns A promise resolving with a Date object or `null` if parsing fails.
 * @throws {McpError} If an unexpected error occurs during parsing.
 * @private
 */
async function parseDateString(
  text: string,
  context: RequestContext,
  refDate?: Date,
): Promise<Date | null> {
  const operation = "parseDateString";
  const logContext = { ...context, operation, inputText: text, refDate };
  logger.debug(`Attempting to parse date string: "${text}"`, logContext);

  return await ErrorHandler.tryCatch(
    async () => {
      const parsedDate = chrono.parseDate(text, refDate, { forwardDate: true });
      if (parsedDate) {
        logger.debug(
          `Successfully parsed "${text}" to ${parsedDate.toISOString()}`,
          logContext,
        );
        return parsedDate;
      } else {
        logger.warning(`Failed to parse date string: "${text}"`, logContext);
        return null;
      }
    },
    {
      operation,
      context: logContext,
      input: { text, refDate },
      // errorCode: BaseErrorCode.PARSING_ERROR, // PARSING_ERROR is not in BaseErrorCode
      errorCode: BaseErrorCode.VALIDATION_ERROR, // Using VALIDATION_ERROR as a substitute
    },
  );
}

/**
 * Parses a natural language date string and returns detailed parsing results.
 * Provides more information than just the Date object, including matched text and components.
 *
 * @param text - The natural language date string to parse.
 * @param context - The request context for logging and error tracking.
 * @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
 * @returns A promise resolving with an array of `chrono.ParsedResult` objects. Empty if no dates found.
 * @throws {McpError} If an unexpected error occurs during parsing.
 * @private
 */
async function parseDateStringDetailed(
  text: string,
  context: RequestContext,
  refDate?: Date,
): Promise<chrono.ParsedResult[]> {
  const operation = "parseDateStringDetailed";
  const logContext = { ...context, operation, inputText: text, refDate };
  logger.debug(
    `Attempting detailed parse of date string: "${text}"`,
    logContext,
  );

  return await ErrorHandler.tryCatch(
    async () => {
      const results = chrono.parse(text, refDate, { forwardDate: true });
      logger.debug(
        `Detailed parse of "${text}" resulted in ${results.length} result(s)`,
        logContext,
      );
      return results;
    },
    {
      operation,
      context: logContext,
      input: { text, refDate },
      // errorCode: BaseErrorCode.PARSING_ERROR, // PARSING_ERROR is not in BaseErrorCode
      errorCode: BaseErrorCode.VALIDATION_ERROR, // Using VALIDATION_ERROR as a substitute
    },
  );
}

/**
 * An object providing date parsing functionalities.
 *
 * @example
 * ```typescript
 * import { dateParser, requestContextService } from './utils'; // Assuming utils/index.js exports these
 * const context = requestContextService.createRequestContext({ operation: 'TestDateParsing' });
 *
 * async function testParsing() {
 *   const dateObj = await dateParser.parseDate("next Friday at 3pm", context);
 *   if (dateObj) {
 *     console.log("Parsed Date:", dateObj.toISOString());
 *   }
 *
 *   const detailedResults = await dateParser.parse("Meeting on 2024-12-25 and another one tomorrow", context);
 *   detailedResults.forEach(result => {
 *     console.log("Detailed Result:", result.text, result.start.date());
 *   });
 * }
 * testParsing();
 * ```
 */
export const dateParser = {
  /**
   * Parses a natural language date string and returns detailed parsing results
   * from `chrono-node`.
   * @param text - The natural language date string to parse.
   * @param context - The request context for logging and error tracking.
   * @param refDate - Optional reference date for parsing relative dates.
   * @returns A promise resolving with an array of `chrono.ParsedResult` objects.
   */
  parse: parseDateStringDetailed,
  /**
   * Parses a natural language date string into a single JavaScript Date object.
   * @param text - The natural language date string to parse.
   * @param context - The request context for logging and error tracking.
   * @param refDate - Optional reference date for parsing relative dates.
   * @returns A promise resolving with a Date object or `null`.
   */
  parseDate: parseDateString,
};

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_add/addKnowledge.ts:
--------------------------------------------------------------------------------

```typescript
import { KnowledgeService } from "../../../services/neo4j/knowledgeService.js";
import { ProjectService } from "../../../services/neo4j/projectService.js";
import {
  BaseErrorCode,
  McpError,
  ProjectErrorCode,
} from "../../../types/errors.js";
import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { ToolContext } from "../../../types/tool.js";
import { AtlasKnowledgeAddInput, AtlasKnowledgeAddSchema } from "./types.js";
import { formatKnowledgeAddResponse } from "./responseFormat.js";

export const atlasAddKnowledge = async (
  input: unknown,
  context: ToolContext,
) => {
  let validatedInput: AtlasKnowledgeAddInput | undefined;
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasAddKnowledge",
    });

  try {
    // Parse and validate input against schema
    validatedInput = AtlasKnowledgeAddSchema.parse(input);

    // Handle single vs bulk knowledge addition based on mode
    if (validatedInput.mode === "bulk") {
      // Execute bulk addition operation
      logger.info("Adding multiple knowledge items", {
        ...reqContext,
        count: validatedInput.knowledge.length,
      });

      const results = {
        success: true,
        message: `Successfully added ${validatedInput.knowledge.length} knowledge items`,
        created: [] as any[],
        errors: [] as any[],
      };

      // Process each knowledge item sequentially
      for (let i = 0; i < validatedInput.knowledge.length; i++) {
        const knowledgeData = validatedInput.knowledge[i];
        try {
          const createdKnowledge = await KnowledgeService.addKnowledge({
            projectId: knowledgeData.projectId,
            text: knowledgeData.text,
            tags: knowledgeData.tags || [],
            domain: knowledgeData.domain,
            citations: knowledgeData.citations || [],
            id: knowledgeData.id, // Use client-provided ID if available
          });

          results.created.push(createdKnowledge);
        } catch (error) {
          results.success = false;
          results.errors.push({
            index: i,
            knowledge: knowledgeData,
            error: {
              code:
                error instanceof McpError
                  ? error.code
                  : BaseErrorCode.INTERNAL_ERROR,
              message: error instanceof Error ? error.message : "Unknown error",
              details: error instanceof McpError ? error.details : undefined,
            },
          });
        }
      }

      if (results.errors.length > 0) {
        results.message = `Added ${results.created.length} of ${validatedInput.knowledge.length} knowledge items with ${results.errors.length} errors`;
      }

      logger.info("Bulk knowledge addition completed", {
        ...reqContext,
        successCount: results.created.length,
        errorCount: results.errors.length,
        knowledgeIds: results.created.map((k) => k.id),
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(results, null, 2));
      } else {
        return formatKnowledgeAddResponse(results);
      }
    } else {
      // Process single knowledge item addition
      const { mode, id, projectId, text, tags, domain, citations } =
        validatedInput;

      logger.info("Adding new knowledge item", {
        ...reqContext,
        projectId,
        domain,
      });

      const knowledge = await KnowledgeService.addKnowledge({
        id, // Use client-provided ID if available
        projectId,
        text,
        tags: tags || [],
        domain,
        citations: citations || [],
      });

      logger.info("Knowledge item added successfully", {
        ...reqContext,
        knowledgeId: knowledge.id,
        projectId,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(knowledge, null, 2));
      } else {
        return formatKnowledgeAddResponse(knowledge);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

    logger.error("Failed to add knowledge item(s)", error as Error, {
      ...reqContext,
      inputReceived: validatedInput ?? input,
    });

    // Handle project not found error specifically
    if (error instanceof Error && error.message.includes("Project with ID")) {
      const projectId =
        validatedInput?.mode === "single"
          ? validatedInput?.projectId
          : validatedInput?.knowledge?.[0]?.projectId;

      throw new McpError(
        ProjectErrorCode.PROJECT_NOT_FOUND,
        `Project not found: ${projectId}`,
        { projectId },
      );
    }

    // Convert other errors to McpError
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Error adding knowledge item(s): ${error instanceof Error ? error.message : "Unknown error"}`,
    );
  }
};

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_update/updateProject.ts:
--------------------------------------------------------------------------------

```typescript
import { ProjectService } from "../../../services/neo4j/projectService.js";
import {
  BaseErrorCode,
  McpError,
  ProjectErrorCode,
} from "../../../types/errors.js";
import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { ToolContext } from "../../../types/tool.js";
import { AtlasProjectUpdateInput, AtlasProjectUpdateSchema } from "./types.js";
import { formatProjectUpdateResponse } from "./responseFormat.js";

export const atlasUpdateProject = async (
  input: unknown,
  context: ToolContext,
) => {
  let validatedInput: AtlasProjectUpdateInput | undefined;
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasUpdateProject",
    });

  try {
    // Parse and validate the input against schema
    validatedInput = AtlasProjectUpdateSchema.parse(input);

    // Process according to operation mode (single or bulk)
    if (validatedInput.mode === "bulk") {
      // Execute bulk update operation
      logger.info("Applying updates to multiple projects", {
        ...reqContext,
        count: validatedInput.projects.length,
      });

      const results = {
        success: true,
        message: `Successfully updated ${validatedInput.projects.length} projects`,
        updated: [] as any[],
        errors: [] as any[],
      };

      // Process each project update sequentially to maintain data consistency
      for (let i = 0; i < validatedInput.projects.length; i++) {
        const projectUpdate = validatedInput.projects[i];
        try {
          // First check if project exists
          const projectExists = await ProjectService.getProjectById(
            projectUpdate.id,
          );

          if (!projectExists) {
            throw new McpError(
              ProjectErrorCode.PROJECT_NOT_FOUND,
              `Project with ID ${projectUpdate.id} not found`,
            );
          }

          // Update the project
          const updatedProject = await ProjectService.updateProject(
            projectUpdate.id,
            projectUpdate.updates,
          );

          results.updated.push(updatedProject);
        } catch (error) {
          results.success = false;
          results.errors.push({
            index: i,
            project: projectUpdate,
            error: {
              code:
                error instanceof McpError
                  ? error.code
                  : BaseErrorCode.INTERNAL_ERROR,
              message: error instanceof Error ? error.message : "Unknown error",
              details: error instanceof McpError ? error.details : undefined,
            },
          });
        }
      }

      if (results.errors.length > 0) {
        results.message = `Updated ${results.updated.length} of ${validatedInput.projects.length} projects with ${results.errors.length} errors`;
      }

      logger.info("Bulk project modification completed", {
        ...reqContext,
        successCount: results.updated.length,
        errorCount: results.errors.length,
        projectIds: results.updated.map((p) => p.id),
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(results, null, 2));
      } else {
        return formatProjectUpdateResponse(results);
      }
    } else {
      // Process single project modification
      const { mode, id, updates } = validatedInput;

      logger.info("Modifying project attributes", {
        ...reqContext,
        id,
        fields: Object.keys(updates),
      });

      // First check if project exists
      const projectExists = await ProjectService.getProjectById(id);

      if (!projectExists) {
        throw new McpError(
          ProjectErrorCode.PROJECT_NOT_FOUND,
          `Project with ID ${id} not found`,
        );
      }

      // Update the project
      const updatedProject = await ProjectService.updateProject(id, updates);

      logger.info("Project modifications applied successfully", {
        ...reqContext,
        projectId: id,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(updatedProject, null, 2));
      } else {
        return formatProjectUpdateResponse(updatedProject);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

    logger.error("Failed to modify project(s)", error as Error, {
      ...reqContext,
      inputReceived: validatedInput ?? input,
    });

    // Handle not found error specifically
    if (error instanceof Error && error.message.includes("not found")) {
      throw new McpError(
        ProjectErrorCode.PROJECT_NOT_FOUND,
        `Project not found: ${error.message}`,
      );
    }

    // Convert generic errors to properly formatted McpError
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Failed to modify project(s): ${error instanceof Error ? error.message : "Unknown error"}`,
    );
  }
};

```

--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/backupUtils.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides utility functions for the backup and restore service,
 * including secure path resolution and backup rotation management.
 * @module src/services/neo4j/backupRestoreService/backupUtils
 */

import { existsSync, mkdirSync, readdirSync, rmSync } from "fs";
import { stat } from "fs/promises";
import path from "path";
import { config } from "../../../config/index.js";
import { logger, requestContextService } from "../../../utils/index.js";

// Define the validated root backup path from config
export const validatedBackupRoot = config.backup.backupPath;

/**
 * Securely resolves a path against a base directory and ensures it stays within that base.
 * @param basePath The absolute, validated base path.
 * @param targetPath The relative or absolute path to resolve.
 * @returns The resolved absolute path if it's within the base path, otherwise null.
 */
export const secureResolve = (
  basePath: string,
  targetPath: string,
): string | null => {
  const resolvedTarget = path.resolve(basePath, targetPath);
  if (
    resolvedTarget.startsWith(basePath + path.sep) ||
    resolvedTarget === basePath
  ) {
    return resolvedTarget;
  }
  const errorContext = requestContextService.createRequestContext({
    operation: "secureResolve.PathViolation",
    targetPath,
    resolvedTarget,
    basePath,
  });
  logger.error(
    `Security Violation: Path "${targetPath}" resolves to "${resolvedTarget}", which is outside the allowed base directory "${basePath}".`,
    new Error("Path security violation"),
    errorContext,
  );
  return null;
};

/**
 * Manages backup rotation, deleting the oldest backups if the count exceeds the limit.
 */
export const manageBackupRotation = async (): Promise<void> => {
  const maxBackups = config.backup.maxBackups;

  const operationName = "manageBackupRotation";
  const baseContext = requestContextService.createRequestContext({
    operation: operationName,
  });

  if (!existsSync(validatedBackupRoot)) {
    logger.warning(
      `Backup root directory does not exist: ${validatedBackupRoot}. Skipping rotation.`,
      { ...baseContext, pathChecked: validatedBackupRoot },
    );
    return;
  }

  try {
    logger.debug(
      `Checking backup rotation in ${validatedBackupRoot}. Max backups: ${maxBackups}`,
      baseContext,
    );

    const dirNames = readdirSync(validatedBackupRoot);

    const processedDirs = await Promise.all(
      dirNames.map(
        async (name): Promise<{ path: string; time: number } | null> => {
          const potentialDirPath = secureResolve(validatedBackupRoot, name);
          if (!potentialDirPath) return null;

          try {
            const stats = await stat(potentialDirPath);
            if (stats.isDirectory()) {
              return { path: potentialDirPath, time: stats.mtime.getTime() };
            }
          } catch (statError: any) {
            if (statError.code !== "ENOENT") {
              logger.warning(
                `Could not stat potential backup directory ${potentialDirPath}: ${statError.message}. Skipping.`,
                {
                  ...baseContext,
                  path: potentialDirPath,
                  errorCode: statError.code,
                },
              );
            }
          }
          return null;
        },
      ),
    );

    const validBackupDirs = processedDirs
      .filter((dir): dir is { path: string; time: number } => dir !== null)
      .sort((a, b) => a.time - b.time);

    const backupsToDeleteCount = validBackupDirs.length - maxBackups;

    if (backupsToDeleteCount > 0) {
      logger.info(
        `Found ${validBackupDirs.length} valid backups. Deleting ${backupsToDeleteCount} oldest backups to maintain limit of ${maxBackups}.`,
        baseContext,
      );
      for (let i = 0; i < backupsToDeleteCount; i++) {
        const dirToDelete = validBackupDirs[i].path;
        if (!dirToDelete.startsWith(validatedBackupRoot + path.sep)) {
          logger.error(
            `Security Error: Attempting to delete directory outside backup root: ${dirToDelete}. Aborting deletion.`,
            new Error("Backup deletion security violation"),
            { ...baseContext, dirToDelete },
          );
          continue;
        }
        try {
          rmSync(dirToDelete, { recursive: true, force: true });
          logger.info(`Deleted old backup directory: ${dirToDelete}`, {
            ...baseContext,
            deletedPath: dirToDelete,
          });
        } catch (rmError) {
          const errorMsg =
            rmError instanceof Error ? rmError.message : String(rmError);
          logger.error(
            `Failed to delete old backup directory ${dirToDelete}: ${errorMsg}`,
            rmError as Error,
            { ...baseContext, dirToDelete },
          );
        }
      }
    } else {
      logger.debug(
        `Backup count (${validBackupDirs.length}) is within the limit (${maxBackups}). No rotation needed.`,
        baseContext,
      );
    }
  } catch (error) {
    const errorMsg = error instanceof Error ? error.message : String(error);
    logger.error(
      `Error during backup rotation management: ${errorMsg}`,
      error as Error,
      baseContext,
    );
  }
};

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_unified_search/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { SearchResultItem } from "../../../services/neo4j/index.js";
import { McpToolResponse, createToolResponse } from "../../../types/mcp.js";
import { UnifiedSearchResponse } from "./types.js";

/**
 * Formatter for unified search responses
 */
class UnifiedSearchFormatter {
  // The input 'responseData' should match the UnifiedSearchResponse type structure.
  format(responseData: UnifiedSearchResponse): string {
    // Destructure the 'results' property as defined in UnifiedSearchResponse
    const { results, total, page, limit, totalPages } = responseData;

    // Create a summary section with pagination info
    const summary =
      `Search Results\n\n` +
      `Found ${total ?? 0} result(s)\n` + // Use nullish coalescing for safety
      `Page ${page ?? 1} of ${totalPages ?? 1} (${limit ?? 0} per page)\n`; // Use nullish coalescing

    // Add a robust check for results being a valid array before accessing length
    if (!Array.isArray(results) || results.length === 0) {
      return `${summary}\nNo matches found for the specified search criteria.`;
    }

    // Group results by entity type for better organization
    const groupedResults: Record<string, SearchResultItem[]> = {};

    results.forEach((result: SearchResultItem) => {
      // Add explicit type here
      if (!groupedResults[result.type]) {
        groupedResults[result.type] = [];
      }
      groupedResults[result.type].push(result);
    });

    // Build formatted output for each entity type group
    let resultsOutput = "";

    Object.entries(groupedResults).forEach(([type, items]) => {
      // Add section heading for this entity type
      resultsOutput += `\n${this.capitalizeFirstLetter(type)} Results (${items.length})\n\n`;

      // Format each result item
      items.forEach((item, index) => {
        const score = Math.round(item.score * 10) / 10; // Round to 1 decimal place
        const relevanceIndicator = this.getRelevanceIndicator(score);

        resultsOutput += `${index + 1}. ${relevanceIndicator} ${item.title}\n`;

        // Add relevant metadata based on entity type
        if (item.type === "project") {
          resultsOutput += `   ID: ${item.id}\n`;
          resultsOutput += `   Type: ${item.entityType}\n`;
          resultsOutput += `   Match: Found in ${item.matchedProperty}\n`;
        } else if (item.type === "task") {
          resultsOutput += `   ID: ${item.id}\n`;
          resultsOutput += `   Project: ${item.projectName || "Unknown"}\n`;
          resultsOutput += `   Type: ${item.entityType}\n`;
          resultsOutput += `   Match: Found in ${item.matchedProperty}\n`;
        } else if (item.type === "knowledge") {
          resultsOutput += `   ID: ${item.id}\n`;
          resultsOutput += `   Project: ${item.projectName || "Unknown"}\n`;
          resultsOutput += `   Domain: ${item.entityType}\n`;
          resultsOutput += `   Match: Found in ${item.matchedProperty}\n`;
        }

        // Add a snippet of the matched content
        if (item.matchedValue) {
          const matchSnippet = this.truncateText(item.matchedValue, 100);
          resultsOutput += `   Content: "${matchSnippet}"\n`;
        }

        // Conditionally add created date if available
        if (item.createdAt) {
          resultsOutput += `   Created: ${new Date(item.createdAt).toLocaleString()}\n`;
        }
        // Add a blank line after each item
        resultsOutput += `\n`;
      });
    });

    // Add help text for pagination
    let paginationHelp = "";
    if (totalPages > 1) {
      paginationHelp = `\nTo view more results, use 'page' parameter (current: ${page}, total pages: ${totalPages}).`;
    }

    return `${summary}${resultsOutput}${paginationHelp}`;
  }

  /**
   * Capitalize the first letter of a string
   */
  private capitalizeFirstLetter(str: string): string {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  /**
   * Get a visual indicator for the relevance score
   */
  private getRelevanceIndicator(score: number): string {
    if (score >= 8) return "🔍 [Highly Relevant]";
    if (score >= 6) return "🔍 [Relevant]";
    if (score >= 4) return "🔍 [Moderately Relevant]";
    return "🔍 [Potentially Relevant]";
  }

  /**
   * Truncate text to a specified length with ellipsis
   */
  private truncateText(
    text: string | null | undefined,
    maxLength: number,
  ): string {
    // Add check to ensure text is a string and handle null/undefined
    if (typeof text !== "string" || text.length === 0) {
      return ""; // Return empty string if text is not valid
    }
    if (text.length <= maxLength) {
      return text;
    }
    return text.substring(0, maxLength - 3) + "...";
  }
}

/**
 * Create a formatted, human-readable response for the atlas_unified_search tool
 *
 * @param data The search response data
 * @param isError Whether this response represents an error condition
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatUnifiedSearchResponse(
  data: UnifiedSearchResponse,
  isError = false,
): McpToolResponse {
  const formatter = new UnifiedSearchFormatter();
  const formattedText = formatter.format(data);
  return createToolResponse(formattedText, isError);
}

```

--------------------------------------------------------------------------------
/src/utils/parsing/jsonParser.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Provides a utility class for parsing potentially partial JSON strings.
 * It wraps the 'partial-json' npm library and includes functionality to handle
 * optional <think>...</think> blocks often found at the beginning of LLM outputs.
 * @module src/utils/parsing/jsonParser
 */
import {
  parse as parsePartialJson,
  Allow as PartialJsonAllow,
} from "partial-json";
import { BaseErrorCode, McpError } from "../../types/errors.js";
import { logger, RequestContext, requestContextService } from "../index.js";

/**
 * Enum mirroring `partial-json`'s `Allow` constants. These specify
 * what types of partial JSON structures are permissible during parsing.
 * They can be combined using bitwise OR (e.g., `Allow.STR | Allow.OBJ`).
 *
 * The available properties are:
 * - `STR`: Allow partial string.
 * - `NUM`: Allow partial number.
 * - `ARR`: Allow partial array.
 * - `OBJ`: Allow partial object.
 * - `NULL`: Allow partial null.
 * - `BOOL`: Allow partial boolean.
 * - `NAN`: Allow partial NaN. (Note: Standard JSON does not support NaN)
 * - `INFINITY`: Allow partial Infinity. (Note: Standard JSON does not support Infinity)
 * - `_INFINITY`: Allow partial -Infinity. (Note: Standard JSON does not support -Infinity)
 * - `INF`: Allow both partial Infinity and -Infinity.
 * - `SPECIAL`: Allow all special values (NaN, Infinity, -Infinity).
 * - `ATOM`: Allow all atomic values (strings, numbers, booleans, null, special values).
 * - `COLLECTION`: Allow all collection values (objects, arrays).
 * - `ALL`: Allow all value types to be partial (default for `partial-json`'s parse).
 * @see {@link https://github.com/promplate/partial-json-parser-js} for more details.
 */
export const Allow = PartialJsonAllow;

/**
 * Regular expression to find a <think> block at the start of a string.
 * Captures content within <think>...</think> (Group 1) and the rest of the string (Group 2).
 * @private
 */
const thinkBlockRegex = /^<think>([\s\S]*?)<\/think>\s*([\s\S]*)$/;

/**
 * Utility class for parsing potentially partial JSON strings.
 * Wraps the 'partial-json' library for robust JSON parsing, handling
 * incomplete structures and optional <think> blocks from LLMs.
 */
export class JsonParser {
  /**
   * Parses a JSON string, which may be partial or prefixed with a <think> block.
   * If a <think> block is present, its content is logged, and parsing proceeds on the
   * remainder. Uses 'partial-json' to handle incomplete JSON.
   *
   * @template T The expected type of the parsed JSON object. Defaults to `any`.
   * @param jsonString - The JSON string to parse.
   * @param allowPartial - Bitwise OR combination of `Allow` constants specifying permissible
   *   partial JSON types. Defaults to `Allow.ALL`.
   * @param context - Optional `RequestContext` for logging and error correlation.
   * @returns The parsed JavaScript value.
   * @throws {McpError} If the string is empty after processing or if `partial-json` fails.
   */
  parse<T = any>(
    jsonString: string,
    allowPartial: number = Allow.ALL,
    context?: RequestContext,
  ): T {
    let stringToParse = jsonString;
    const match = jsonString.match(thinkBlockRegex);

    if (match) {
      const thinkContent = match[1].trim();
      const restOfString = match[2];

      const logContext =
        context ||
        requestContextService.createRequestContext({
          operation: "JsonParser.thinkBlock",
        });
      if (thinkContent) {
        logger.debug("LLM <think> block detected and logged.", {
          ...logContext,
          thinkContent,
        });
      } else {
        logger.debug("Empty LLM <think> block detected.", logContext);
      }
      stringToParse = restOfString;
    }

    stringToParse = stringToParse.trim();

    if (!stringToParse) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        "JSON string is empty after removing <think> block and trimming.",
        context,
      );
    }

    try {
      return parsePartialJson(stringToParse, allowPartial) as T;
    } catch (error: any) {
      const errorLogContext =
        context ||
        requestContextService.createRequestContext({
          operation: "JsonParser.parseError",
        });
      logger.error("Failed to parse JSON content.", {
        ...errorLogContext,
        errorDetails: error.message,
        contentAttempted: stringToParse.substring(0, 200),
      });

      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        `Failed to parse JSON: ${error.message}`,
        {
          ...context,
          originalContentSample:
            stringToParse.substring(0, 200) +
            (stringToParse.length > 200 ? "..." : ""),
          rawError: error instanceof Error ? error.stack : String(error),
        },
      );
    }
  }
}

/**
 * Singleton instance of the `JsonParser`.
 * Use this instance to parse JSON strings, with support for partial JSON and <think> blocks.
 * @example
 * ```typescript
 * import { jsonParser, Allow, requestContextService } from './utils';
 * const context = requestContextService.createRequestContext({ operation: 'TestJsonParsing' });
 *
 * const fullJson = '{"key": "value"}';
 * const parsedFull = jsonParser.parse(fullJson, Allow.ALL, context);
 * console.log(parsedFull); // Output: { key: 'value' }
 *
 * const partialObject = '<think>This is a thought.</think>{"key": "value", "arr": [1,';
 * try {
 *   const parsedPartial = jsonParser.parse(partialObject, undefined, context);
 *   console.log(parsedPartial);
 * } catch (e) {
 *   console.error("Parsing partial object failed:", e);
 * }
 * ```
 */
export const jsonParser = new JsonParser();

```

--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/scripts/db-import.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
import { existsSync, lstatSync } from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { importDatabase } from "../index.js"; // Adjusted path
import { closeNeo4jConnection } from "../../index.js"; // Adjusted path
import { logger, requestContextService } from "../../../../utils/index.js"; // Adjusted path
import { config } from "../../../../config/index.js"; // Added config import
import { McpLogLevel } from "../../../../utils/internal/logger.js"; // Added McpLogLevel import

/**
 * DB Import Script
 * ================
 *
 * Description:
 *   Imports data from a specified backup directory into the Neo4j database,
 *   overwriting existing data. Validates paths for security.
 *
 * Usage:
 *   - Update package.json script for db:import to point to the new path.
 *   - Run directly: npm run db:import <path_to_backup_directory>
 *   - Example: npm run db:import ./backups/atlas-backup-20230101120000
 */

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Project root is now 5 levels up from src/services/neo4j/backupRestoreService/scripts/
const projectRoot = path.resolve(__dirname, "../../../../../");

/**
 * Validates the provided backup directory path.
 * Ensures the path is within the project root and is a directory.
 * @param backupDir Path to the backup directory.
 * @returns True if valid, false otherwise.
 */
const isValidBackupDir = (backupDir: string): boolean => {
  const resolvedBackupDir = path.resolve(backupDir);
  const reqContext = requestContextService.createRequestContext({
    operation: "isValidBackupDir.validation",
    backupDir: resolvedBackupDir,
    projectRoot,
  });

  if (
    !resolvedBackupDir.startsWith(projectRoot + path.sep) &&
    resolvedBackupDir !== projectRoot
  ) {
    logger.error(
      `Invalid backup directory: Path is outside the project boundary.`,
      new Error("Path security violation: outside project boundary."),
      { ...reqContext, pathChecked: resolvedBackupDir },
    );
    return false;
  }

  if (
    !existsSync(resolvedBackupDir) ||
    !lstatSync(resolvedBackupDir).isDirectory()
  ) {
    logger.error(
      `Invalid backup directory: Path does not exist or is not a directory.`,
      new Error("Path validation failed: not a directory or does not exist."),
      { ...reqContext, pathChecked: resolvedBackupDir },
    );
    return false;
  }

  const expectedFiles = [
    "projects.json",
    "tasks.json",
    "knowledge.json",
    "relationships.json",
    "full-export.json", // Check for full-export as well, though import logic handles its absence
  ];
  let foundAtLeastOne = false;
  for (const file of expectedFiles) {
    const filePath = path.join(resolvedBackupDir, file);
    const resolvedFilePath = path.resolve(filePath);

    if (
      !resolvedFilePath.startsWith(resolvedBackupDir + path.sep) &&
      resolvedFilePath !== resolvedBackupDir
    ) {
      logger.warning(
        `Skipping check for potentially unsafe file path: ${resolvedFilePath} (outside ${resolvedBackupDir})`,
        { ...reqContext, filePath: resolvedFilePath },
      );
      continue;
    }

    if (existsSync(resolvedFilePath)) {
      foundAtLeastOne = true;
      // For full-export, its presence is enough. For others, we just note if they are missing.
      if (file !== "full-export.json" && !existsSync(resolvedFilePath)) {
        logger.warning(
          `Expected backup file not found: ${resolvedFilePath}. Import might be incomplete if not using full-export.json.`,
          { ...reqContext, missingFile: resolvedFilePath },
        );
      }
    } else if (file !== "full-export.json") {
      // Only warn if individual files are missing and full-export isn't the one being checked
      logger.warning(
        `Expected backup file not found: ${resolvedFilePath}. Import might be incomplete if not using full-export.json.`,
        { ...reqContext, missingFile: resolvedFilePath },
      );
    }
  }
  // If neither full-export.json nor any of the individual main files are found, it's likely not a valid backup.
  // However, the import logic itself checks for full-export first, then individual files.
  // This validation is more of a sanity check.
  return true;
};

/**
 * Manual import script entry point.
 */
const runManualImport = async () => {
  await logger.initialize(config.logLevel as McpLogLevel);

  const args = process.argv.slice(2);

  if (args.length !== 1) {
    logger.error(
      "Usage: npm run db:import <path_to_backup_directory>",
      new Error("Invalid arguments"),
      requestContextService.createRequestContext({
        operation: "runManualImport.argCheck",
      }),
    );
    process.exit(1);
  }

  const userInputPath = args[0];
  const resolvedBackupDir = path.resolve(userInputPath);

  logger.info(`Attempting manual database import from: ${resolvedBackupDir}`);
  logger.warning(
    "!!! THIS WILL OVERWRITE ALL EXISTING DATA IN THE DATABASE !!!",
  );

  if (!isValidBackupDir(resolvedBackupDir)) {
    process.exit(1);
  }

  try {
    await importDatabase(resolvedBackupDir); // importDatabase itself uses validatedBackupRoot internally
    logger.info(
      `Manual import from ${resolvedBackupDir} completed successfully.`,
    );
  } catch (error) {
    const reqContext = requestContextService.createRequestContext({
      operation: "runManualImport.catch",
      backupDir: resolvedBackupDir,
    });
    const errorToLog =
      error instanceof Error ? error : new Error(JSON.stringify(error));
    logger.error("Manual database import failed:", errorToLog, reqContext);
    process.exitCode = 1;
  } finally {
    logger.info("Closing Neo4j connection...");
    await closeNeo4jConnection();
    logger.info("Neo4j connection closed.");
  }
};

runManualImport();

```

--------------------------------------------------------------------------------
/src/mcp/resources/projects/projectResources.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { ProjectService } from "../../../services/neo4j/projectService.js";
import {
  BaseErrorCode,
  McpError,
  ProjectErrorCode,
} from "../../../types/errors.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import {
  ResourceTemplates,
  ResourceURIs,
  toProjectResource,
} from "../types.js";

/**
 * Register Project Resources
 *
 * This function registers resource endpoints for the Projects entity
 * - GET atlas://projects - List all projects
 * - GET atlas://projects/{projectId} - Get specific project by ID
 *
 * @param server The MCP server instance
 */
export function registerProjectResources(server: McpServer) {
  // List all projects
  server.resource(
    "projects-list",
    ResourceURIs.PROJECTS,
    {
      name: "All Projects",
      description:
        "List of all projects in the Atlas platform with pagination support",
      mimeType: "application/json",
    },
    async (uri) => {
      const reqContext = requestContextService.createRequestContext({
        operation: "listAllProjects",
        resourceUri: uri.href,
      });
      try {
        logger.info("Listing projects", { ...reqContext, uri: uri.href });

        // Parse query parameters
        const queryParams = new URLSearchParams(uri.search);
        const filters: Record<string, any> = {};

        // Parse status parameter
        const status = queryParams.get("status");
        if (status) {
          filters.status = String(status);
        }

        // Parse taskType parameter
        const taskType = queryParams.get("taskType");
        if (taskType) {
          filters.taskType = String(taskType);
        }

        // Parse pagination parameters
        const page = queryParams.has("page")
          ? parseInt(queryParams.get("page") || "1", 10)
          : 1;

        const limit = queryParams.has("limit")
          ? parseInt(queryParams.get("limit") || "20", 10)
          : 20;

        // Add pagination to filters
        filters.page = page;
        filters.limit = limit;

        // Use ProjectService instead of direct database access
        const result = await ProjectService.getProjects(filters);

        // Convert Neo4j projects to project resources
        const projectResources = result.data.map(toProjectResource);

        // Create pagination metadata using result from service
        const pagination = {
          total: result.total,
          page: result.page,
          limit: result.limit,
          totalPages: result.totalPages,
        };

        logger.info(
          `Found ${result.total} projects, returning page ${result.page} with ${projectResources.length} items`,
          {
            ...reqContext,
            totalProjects: result.total,
            returnedCount: projectResources.length,
            page: result.page,
          },
        );

        return {
          contents: [
            {
              uri: uri.href,
              mimeType: "application/json",
              text: JSON.stringify(
                {
                  projects: projectResources,
                  pagination,
                },
                null,
                2,
              ),
            },
          ],
        };
      } catch (error) {
        logger.error("Error listing projects", error as Error, {
          ...reqContext,
          // error is now part of the Error object passed to logger
          uri: uri.href,
        });

        throw new McpError(
          BaseErrorCode.INTERNAL_ERROR,
          `Failed to list projects: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    },
  );

  // Get project by ID
  server.resource(
    "project-by-id",
    ResourceTemplates.PROJECT,
    {
      name: "Project by ID",
      description: "Retrieves a single project by its unique identifier",
      mimeType: "application/json",
    },
    async (uri, params) => {
      const reqContext = requestContextService.createRequestContext({
        operation: "getProjectById",
        resourceUri: uri.href,
        projectIdParam: params.projectId,
      });
      try {
        const projectId = params.projectId as string;

        logger.info("Fetching project by ID", {
          ...reqContext,
          projectId, // Already in reqContext
          uri: uri.href, // Already in reqContext
        });

        if (!projectId) {
          throw new McpError(
            BaseErrorCode.VALIDATION_ERROR,
            "Project ID is required",
          );
        }

        // Use ProjectService instead of direct database access
        const project = await ProjectService.getProjectById(projectId);

        if (!project) {
          throw new McpError(
            ProjectErrorCode.PROJECT_NOT_FOUND,
            `Project with ID ${projectId} not found`,
            { projectId },
          );
        }

        // Convert to resource format
        const projectResource = toProjectResource(project);

        logger.info("Retrieved project successfully", {
          ...reqContext,
          projectId: project.id, // Already in reqContext
        });

        return {
          contents: [
            {
              uri: uri.href,
              mimeType: "application/json",
              text: JSON.stringify(projectResource, null, 2),
            },
          ],
        };
      } catch (error) {
        // Handle specific error cases
        if (error instanceof McpError) {
          throw error;
        }

        logger.error("Error fetching project by ID", error as Error, {
          ...reqContext,
          // error is now part of the Error object passed to logger
          parameters: params,
        });

        throw new McpError(
          BaseErrorCode.INTERNAL_ERROR,
          `Failed to fetch project: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    },
  );
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_create/types.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";
import {
  McpToolResponse,
  ProjectStatus,
  ResponseFormat,
  TaskType,
  createProjectStatusEnum,
  createResponseFormatEnum,
  createTaskTypeEnum,
} from "../../../types/mcp.js";

export const ProjectSchema = z.object({
  id: z
    .string()
    .optional()
    .describe("Optional client-generated project ID or identifier"),
  name: z
    .string()
    .min(1)
    .max(100)
    .describe("Clear, descriptive project name (1-100 characters)"),
  description: z
    .string()
    .describe(
      "Comprehensive project overview with scope, goals, and implementation details",
    ),
  status: createProjectStatusEnum()
    .default(ProjectStatus.ACTIVE)
    .describe("Current project state for tracking progress (Default: active)"),
  urls: z
    .array(
      z.object({
        title: z.string(),
        url: z.string(),
      }),
    )
    .optional()
    .describe(
      "Links to relevant documentation, specifications, and resources (e.g., 'https://example.com' or 'file://path/to/index.ts')",
    ),
  completionRequirements: z
    .string()
    .describe("Clear definition of done with measurable success criteria"),
  dependencies: z
    .array(z.string())
    .optional()
    .describe(
      "Project IDs that must be completed before this project can begin",
    ),
  outputFormat: z
    .string()
    .describe("Required format and structure for project deliverables"),
  taskType: createTaskTypeEnum()
    .or(z.string())
    .describe(
      "Classification of project purpose for organization and workflow",
    ),
});

const SingleProjectSchema = z
  .object({
    mode: z.literal("single"),
    id: z.string().optional(),
    name: z.string().min(1).max(100),
    description: z.string(),
    status: createProjectStatusEnum().optional().default(ProjectStatus.ACTIVE),
    urls: z
      .array(
        z.object({
          title: z.string(),
          url: z.string(),
        }),
      )
      .optional(),
    completionRequirements: z.string(),
    dependencies: z.array(z.string()).optional(),
    outputFormat: z.string(),
    taskType: createTaskTypeEnum().or(z.string()),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe("Creates a single project with comprehensive details and metadata");

const BulkProjectSchema = z
  .object({
    mode: z.literal("bulk"),
    projects: z
      .array(ProjectSchema)
      .min(1)
      .max(100)
      .describe(
        "Collection of project definitions to create in a single operation",
      ),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe(
    "Create multiple related projects in a single efficient transaction",
  );

// Schema shapes for tool registration
export const AtlasProjectCreateSchemaShape = {
  mode: z
    .enum(["single", "bulk"])
    .describe(
      "Operation mode - 'single' for creating one detailed project with full metadata, 'bulk' for efficiently initializing multiple related projects in a single transaction",
    ),
  id: z
    .string()
    .optional()
    .describe(
      "Client-generated unique project identifier for consistent cross-referencing (recommended for mode='single', system will generate if not provided)",
    ),
  name: z
    .string()
    .min(1)
    .max(100)
    .optional()
    .describe(
      "Clear, descriptive project name for display and identification (1-100 characters) (required for mode='single')",
    ),
  description: z
    .string()
    .optional()
    .describe(
      "Comprehensive project overview detailing scope, objectives, approach, and implementation details (required for mode='single')",
    ),
  status: createProjectStatusEnum()
    .optional()
    .describe(
      "Project lifecycle state for tracking progress and filtering (Default: active)",
    ),
  urls: z
    .array(
      z.object({
        title: z.string(),
        url: z.string(),
      }),
    )
    .optional()
    .describe(
      "Array of titled links to relevant documentation, specifications, code repositories, and external resources (supports web URLs and file paths)",
    ),
  completionRequirements: z
    .string()
    .optional()
    .describe(
      "Quantifiable success criteria and acceptance requirements that define when the project is considered complete (required for mode='single')",
    ),
  dependencies: z
    .array(z.string())
    .optional()
    .describe(
      "Array of project IDs that must be completed before this project can begin, establishing workflow prerequisites and sequencing",
    ),
  outputFormat: z
    .string()
    .optional()
    .describe(
      "Expected format and structure specification for the project's final deliverables and artifacts (required for mode='single')",
    ),
  taskType: createTaskTypeEnum()
    .or(z.string())
    .optional()
    .describe(
      "Project type classification for workflow organization, filtering, and reporting (options: research, generation, analysis, integration, or custom type) (required for mode='single')",
    ),
  projects: z
    .array(ProjectSchema)
    .min(1)
    .max(100)
    .optional()
    .describe(
      "Array of complete project definition objects to create in a single transaction (supports 1-100 projects, required for mode='bulk')",
    ),
  responseFormat: createResponseFormatEnum()
    .optional()
    .describe(
      "Desired response format: 'formatted' (default string) or 'json' (raw object)",
    ),
} as const;

// Schema for validation
export const AtlasProjectCreateSchema = z.discriminatedUnion("mode", [
  SingleProjectSchema,
  BulkProjectSchema,
]);

export type AtlasProjectCreateInput = z.infer<typeof AtlasProjectCreateSchema>;
export type ProjectInput = z.infer<typeof ProjectSchema>;
export type AtlasProjectCreateResponse = McpToolResponse;

```

--------------------------------------------------------------------------------
/src/webui/logic/main.js:
--------------------------------------------------------------------------------

```javascript
/**
 * @fileoverview Main application entry point. Initializes the app and sets up event handlers.
 * @module src/webui/logic/main
 */

import { dom } from "./dom-elements.js";
import { state } from "./app-state.js"; // utils is also exported from app-state but not directly used here
import { uiHelpers, renderHelpers } from "./ui-service.js";
import { api } from "./api-service.js";

/**
 * Manages application event handling.
 * @type {object}
 */
const eventHandlers = {
  /**
   * Handles changes to the project selection dropdown.
   * @param {Event} event - The change event.
   */
  handleProjectSelectChange: (event) => {
    if (event.target && event.target.value) {
      const projectId = event.target.value;
      api.fetchProjectDetails(projectId);
      localStorage.setItem("lastSelectedProjectId", projectId);
    }
  },

  /**
   * Handles clicks on the refresh button.
   */
  handleRefreshClick: () => {
    api.fetchProjects();
  },

  /**
   * Handles changes to the theme toggle checkbox.
   */
  handleThemeToggleChange: () => {
    uiHelpers.toggleTheme();
  },

  /**
   * Handles clicks on the task view mode toggle button.
   */
  handleTaskViewModeToggle: () => {
    state.tasksViewMode =
      state.tasksViewMode === "detailed" ? "compact" : "detailed";
    uiHelpers.updateToggleButton(
      dom.taskViewModeToggle,
      state.tasksViewMode === "compact",
      "Detailed View",
      "Compact View",
    );
    if (dom.tasksContent) {
      // Ensure element exists
      renderHelpers.tasks(
        state.currentTasks,
        dom.tasksContent,
        state.tasksViewMode,
      );
    }
  },

  /**
   * Handles clicks on the knowledge view mode toggle button.
   */
  handleKnowledgeViewModeToggle: () => {
    state.knowledgeViewMode =
      state.knowledgeViewMode === "detailed" ? "compact" : "detailed";
    uiHelpers.updateToggleButton(
      dom.knowledgeViewModeToggle,
      state.knowledgeViewMode === "compact",
      "Detailed View",
      "Compact View",
    );
    if (dom.knowledgeContent) {
      // Ensure element exists
      renderHelpers.knowledgeItems(
        state.currentKnowledgeItems,
        dom.knowledgeContent,
        state.knowledgeViewMode,
      );
    }
  },

  /**
   * Handles clicks on the task flow toggle button.
   */
  handleTaskFlowToggle: () => {
    state.showingTaskFlow = !state.showingTaskFlow;
    uiHelpers.setDisplay(dom.tasksContent, !state.showingTaskFlow);
    uiHelpers.setDisplay(dom.taskFlowContainer, state.showingTaskFlow);
    uiHelpers.updateToggleButton(
      dom.taskFlowToggle,
      state.showingTaskFlow,
      "View Task List",
      "View Task Flow",
    );
    if (state.showingTaskFlow && dom.taskFlowContainer) {
      // Ensure element exists
      renderHelpers.taskFlow(state.currentTasks, dom.taskFlowContainer);
    }
  },

  /**
   * Sets up all event listeners for the application.
   */
  setup: () => {
    // Ensure DOM elements exist before adding listeners
    if (dom.projectSelect) {
      dom.projectSelect.addEventListener(
        "change",
        eventHandlers.handleProjectSelectChange,
      );
    }
    if (dom.refreshButton) {
      dom.refreshButton.addEventListener(
        "click",
        eventHandlers.handleRefreshClick,
      );
    }
    if (dom.themeCheckbox) {
      dom.themeCheckbox.addEventListener(
        "change",
        eventHandlers.handleThemeToggleChange,
      );
    }
    if (dom.themeLabel) {
      // Allow clicking label to toggle checkbox
      dom.themeLabel.addEventListener("click", () => {
        if (dom.themeCheckbox) dom.themeCheckbox.click();
      });
    }
    if (dom.taskViewModeToggle) {
      dom.taskViewModeToggle.addEventListener(
        "click",
        eventHandlers.handleTaskViewModeToggle,
      );
    }
    if (dom.knowledgeViewModeToggle) {
      dom.knowledgeViewModeToggle.addEventListener(
        "click",
        eventHandlers.handleKnowledgeViewModeToggle,
      );
    }
    if (dom.taskFlowToggle) {
      dom.taskFlowToggle.addEventListener(
        "click",
        eventHandlers.handleTaskFlowToggle,
      );
    }
  },
};

/**
 * Waits for the Neo4j global driver to be available.
 * @param {number} [timeout=5000] - Maximum time to wait in milliseconds.
 * @returns {Promise<void>} Resolves when neo4j is available, or rejects on timeout.
 * @private
 */
async function waitForNeo4j(timeout = 5000) {
  const startTime = Date.now();
  while (typeof neo4j === "undefined") {
    if (Date.now() - startTime > timeout) {
      console.error("Neo4j driver failed to load within timeout.");
      throw new Error("Neo4j driver failed to load within timeout.");
    }
    await new Promise((resolve) => setTimeout(resolve, 100)); // Wait 100ms
  }
  console.log("Neo4j driver detected.");
}

/**
 * Initializes the application.
 * Loads theme, sets up event handlers, connects to Neo4j, and fetches initial data.
 * @async
 */
async function initApp() {
  uiHelpers.loadTheme(); // Apply saved theme and initialize Mermaid
  eventHandlers.setup(); // Setup event listeners

  // Initialize toggle button texts, ensuring buttons exist
  uiHelpers.updateToggleButton(
    dom.taskViewModeToggle,
    state.tasksViewMode === "compact",
    "Detailed View",
    "Compact View",
  );
  uiHelpers.updateToggleButton(
    dom.knowledgeViewModeToggle,
    state.knowledgeViewMode === "compact",
    "Detailed View",
    "Compact View",
  );
  uiHelpers.updateToggleButton(
    dom.taskFlowToggle,
    state.showingTaskFlow,
    "View Task List",
    "View Task Flow",
  );

  try {
    await waitForNeo4j(); // Wait for the driver to be loaded
    const connected = await api.connect();
    if (connected) {
      api.fetchProjects();
    }
  } catch (error) {
    console.error("Initialization error:", error);
    // Ensure uiHelpers is available and dom.errorMessageDiv is checked within showError
    uiHelpers.showError(
      `App Initialization Error: ${error.message}. Check console.`,
      true,
    );
  }
}

// Start the application once the DOM is fully loaded
document.addEventListener("DOMContentLoaded", initApp);

```

--------------------------------------------------------------------------------
/src/mcp/resources/types.ts:
--------------------------------------------------------------------------------

```typescript
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import {
  Neo4jKnowledge,
  Neo4jProject,
  Neo4jTask,
} from "../../services/neo4j/types.js";
import { logger, requestContextService } from "../../utils/index.js"; // Import requestContextService

/**
 * Resource URIs for the Atlas MCP resources
 */
export const ResourceURIs = {
  // Project resources
  PROJECTS: "atlas://projects",
  PROJECT_TEMPLATE: "atlas://projects/{projectId}",

  // Task resources
  TASKS: "atlas://tasks",
  TASKS_BY_PROJECT: "atlas://projects/{projectId}/tasks",
  TASK_TEMPLATE: "atlas://tasks/{taskId}",

  // Knowledge resources
  KNOWLEDGE: "atlas://knowledge",
  KNOWLEDGE_BY_PROJECT: "atlas://projects/{projectId}/knowledge",
  KNOWLEDGE_TEMPLATE: "atlas://knowledge/{knowledgeId}",
};

/**
 * Resource templates for the Atlas MCP resources
 */
export const ResourceTemplates = {
  // Project resource templates
  PROJECT: new ResourceTemplate(ResourceURIs.PROJECT_TEMPLATE, {
    list: () => ({
      resources: [
        {
          uri: ResourceURIs.PROJECTS,
          name: "All Projects",
          description: "List of all projects in the Atlas platform",
        },
      ],
    }),
  }),

  // Task resource templates
  TASK: new ResourceTemplate(ResourceURIs.TASK_TEMPLATE, {
    list: () => ({
      resources: [
        {
          uri: ResourceURIs.TASKS,
          name: "All Tasks",
          description: "List of all tasks in the Atlas platform",
        },
      ],
    }),
  }),
  TASKS_BY_PROJECT: new ResourceTemplate(ResourceURIs.TASKS_BY_PROJECT, {
    list: undefined,
  }),

  // Knowledge resource templates
  KNOWLEDGE: new ResourceTemplate(ResourceURIs.KNOWLEDGE_TEMPLATE, {
    list: () => ({
      resources: [
        {
          uri: ResourceURIs.KNOWLEDGE,
          name: "All Knowledge",
          description: "List of all knowledge items in the Atlas platform",
        },
      ],
    }),
  }),
  KNOWLEDGE_BY_PROJECT: new ResourceTemplate(
    ResourceURIs.KNOWLEDGE_BY_PROJECT,
    {
      list: undefined,
    },
  ),
};

/**
 * Project resource response interface
 */
export interface ProjectResource {
  id: string;
  name: string;
  description: string;
  status: string;
  urls: Array<{ title: string; url: string }>;
  completionRequirements: string;
  outputFormat: string;
  taskType: string;
  createdAt: string;
  updatedAt: string;
}

/**
 * Task resource response interface
 */
export interface TaskResource {
  id: string;
  projectId: string;
  title: string;
  description: string;
  priority: string;
  status: string;
  assignedTo: string | null;
  urls: Array<{ title: string; url: string }>;
  tags: string[];
  completionRequirements: string;
  outputFormat: string;
  taskType: string;
  createdAt: string;
  updatedAt: string;
}

/**
 * Knowledge resource response interface
 */
export interface KnowledgeResource {
  id: string;
  projectId: string;
  text: string;
  tags: string[];
  domain: string;
  citations: string[];
  createdAt: string;
  updatedAt: string;
}

/**
 * Convert Neo4j Project to Project Resource
 */
export function toProjectResource(project: Neo4jProject): ProjectResource {
  const reqContext = requestContextService.createRequestContext({
    operation: "toProjectResource",
    projectId: project.id,
  });
  // Log the incoming project structure for debugging
  logger.debug("Converting project to resource:", {
    ...reqContext,
    projectData: project,
  });

  // Ensure all fields are properly extracted
  const resource: ProjectResource = {
    id: project.id,
    name: project.name,
    description: project.description,
    status: project.status,
    urls: project.urls || [],
    completionRequirements: project.completionRequirements,
    outputFormat: project.outputFormat,
    taskType: project.taskType,
    createdAt: project.createdAt,
    updatedAt: project.updatedAt,
  };

  logger.debug("Created project resource:", {
    ...reqContext,
    projectResource: resource,
  });
  return resource;
}

/**
 * Convert Neo4j Task (with added assignedToUserId) to Task Resource
 */
export function toTaskResource(
  task: Neo4jTask & { assignedToUserId: string | null },
): TaskResource {
  const reqContext = requestContextService.createRequestContext({
    operation: "toTaskResource",
    taskId: task.id,
  });
  // Log the incoming task structure for debugging
  logger.debug("Converting task to resource:", {
    ...reqContext,
    taskData: task,
  });

  const resource: TaskResource = {
    id: task.id,
    projectId: task.projectId,
    title: task.title,
    description: task.description,
    priority: task.priority,
    status: task.status,
    assignedTo: task.assignedToUserId, // Use assignedToUserId from the input object
    urls: task.urls || [],
    tags: task.tags || [],
    completionRequirements: task.completionRequirements,
    outputFormat: task.outputFormat,
    taskType: task.taskType,
    createdAt: task.createdAt,
    updatedAt: task.updatedAt,
  };

  logger.debug("Created task resource:", {
    ...reqContext,
    taskResource: resource,
  });
  return resource;
}

/**
 * Convert Neo4j Knowledge (with added domain/citations) to Knowledge Resource
 */
export function toKnowledgeResource(
  knowledge: Neo4jKnowledge & { domain: string | null; citations: string[] },
): KnowledgeResource {
  const reqContext = requestContextService.createRequestContext({
    operation: "toKnowledgeResource",
    knowledgeId: knowledge.id,
  });
  // Log the incoming knowledge structure for debugging
  logger.debug("Converting knowledge to resource:", {
    ...reqContext,
    knowledgeData: knowledge,
  });

  const resource: KnowledgeResource = {
    id: knowledge.id,
    projectId: knowledge.projectId,
    text: knowledge.text,
    tags: knowledge.tags || [],
    domain: knowledge.domain || "", // Use domain from the input object, default to empty string if null
    citations: knowledge.citations || [], // Use citations from the input object
    createdAt: knowledge.createdAt,
    updatedAt: knowledge.updatedAt,
  };

  logger.debug("Created knowledge resource:", {
    ...reqContext,
    knowledgeResource: resource,
  });
  return resource;
}

```

--------------------------------------------------------------------------------
/src/webui/index.html:
--------------------------------------------------------------------------------

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Atlas Projects Live View</title>
    <link rel="stylesheet" href="styling/theme.css" />
    <link rel="stylesheet" href="styling/base.css" />
    <link rel="stylesheet" href="styling/layout.css" />
    <link rel="stylesheet" href="styling/components.css" />
    <!-- Mermaid JS CDN -->
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
  </head>
  <body>
    <div id="app">
      <header class="app-header">
        <div class="theme-switch-wrapper">
          <label
            class="theme-switch"
            for="theme-checkbox"
            aria-label="Toggle color theme"
          >
            <input type="checkbox" id="theme-checkbox" />
            <div class="slider round"></div>
          </label>
          <span class="theme-label" id="theme-label-text">Toggle Theme</span>
        </div>
        <h1>Atlas Projects Live View</h1>
      </header>

      <main>
        <section class="controls-section" aria-labelledby="controls-heading">
          <h2 id="controls-heading" class="visually-hidden">
            Project Controls
          </h2>
          <div class="controls-container">
            <label for="project-select">Select a Project:</label>
            <select
              id="project-select"
              aria-label="Select a project to view its details"
            >
              <option value="">Loading projects...</option>
            </select>
            <button id="refresh-button" type="button">Refresh Projects</button>
          </div>
        </section>

        <section
          id="project-details-container"
          class="data-section hidden"
          aria-labelledby="project-details-heading"
        >
          <h2 id="project-details-heading">Project Details</h2>
          <div id="details-content" class="details-grid"></div>
        </section>

        <section
          id="tasks-container"
          class="data-section hidden"
          aria-labelledby="tasks-heading"
        >
          <div class="section-header">
            <h3 id="tasks-heading">Tasks</h3>
            <div class="view-controls">
              <button
                class="view-toggle-button"
                id="task-view-mode-toggle"
                type="button"
                aria-pressed="false"
                aria-controls="tasks-content"
              >
                Compact View
              </button>
              <button
                class="view-toggle-button"
                id="task-flow-toggle"
                type="button"
                aria-pressed="false"
                aria-controls="task-flow-container tasks-content"
              >
                View Task Flow
              </button>
            </div>
          </div>
          <div id="tasks-content" role="region" aria-live="polite"></div>
          <div
            id="task-flow-container"
            class="hidden mermaid-container"
            role="region"
            aria-live="polite"
          >
            <!-- Mermaid chart will be rendered here -->
          </div>
        </section>

        <section
          id="project-task-board-container"
          class="data-section hidden"
          aria-labelledby="project-task-board-heading"
        >
          <h2 id="project-task-board-heading">Project Task Board</h2>
          <div
            id="project-task-board-content"
            class="task-board-grid"
            role="region"
            aria-live="polite"
          >
            <!-- Task board columns will be rendered here -->
          </div>
        </section>

        <section
          id="knowledge-container"
          class="data-section hidden"
          aria-labelledby="knowledge-heading"
        >
          <div class="section-header">
            <h3 id="knowledge-heading">Knowledge Items</h3>
            <div class="view-controls">
              <button
                class="view-toggle-button"
                id="knowledge-view-mode-toggle"
                type="button"
                aria-pressed="false"
                aria-controls="knowledge-content"
              >
                Compact View
              </button>
            </div>
          </div>
          <div id="knowledge-content" role="region" aria-live="polite"></div>
        </section>

        <section
          id="data-explorer-container"
          class="data-section hidden"
          aria-labelledby="data-explorer-heading"
        >
          <h2 id="data-explorer-heading">Data Explorer</h2>
          <div class="controls-container">
            <label for="node-label-select">Select Node Type:</label>
            <select
              id="node-label-select"
              aria-label="Select a node type to explore"
            >
              <option value="">Loading node types...</option>
            </select>
            <button id="refresh-node-types-button" type="button">
              Refresh Types
            </button>
          </div>
          <div id="data-explorer-content" role="region" aria-live="polite">
            <!-- Nodes of selected type will be rendered here -->
          </div>
          <div
            id="data-explorer-details"
            class="details-grid"
            role="region"
            aria-live="polite"
          >
            <!-- Details of a selected node will be rendered here -->
          </div>
        </section>
      </main>

      <footer class="app-footer">
        <div
          id="error-message"
          class="error hidden"
          role="alert"
          aria-live="assertive"
        ></div>
        <div id="connection-status">
          Connection Status: <span id="neo4j-status">Not Connected</span>
        </div>
      </footer>
    </div>

    <!-- Neo4j Browser Driver via CDN -->
    <script src="https://unpkg.com/neo4j-driver@5/lib/browser/neo4j-web.min.js"></script>

    <!-- 
        Optional: User can manually provide credentials here if not included in prompt
        These will be overridden by script.js if window.NEO4J_... variables are already set there.
        <script>
            // window.NEO4J_URI = "bolt://localhost:7687";
            // window.NEO4J_USER = "neo4j";
            // window.NEO4J_PASSWORD = "password2";
        </script> 
    -->
    <script type="module" src="logic/main.js"></script>
  </body>
</html>

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_deep_research/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { McpToolResponse, createToolResponse } from "../../../types/mcp.js"; // Import createToolResponse
import { AtlasDeepResearchInput, DeepResearchResult } from "./types.js";

/**
 * Defines a generic interface for formatting data into a string.
 * This was previously imported but is now defined locally as the original seems to be removed.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Base response formatter for the `atlas_deep_research` tool.
 * This formatter provides a basic structure for the output, primarily using
 * the data returned by the core `deepResearch` function.
 * It's designed to be used within `formatDeepResearchResponse` which adds
 * contextual information from the original tool input.
 */
export const DeepResearchBaseFormatter: ResponseFormatter<DeepResearchResult> =
  {
    format: (data: DeepResearchResult): string => {
      // This base format method only uses the 'data' part of the result.
      // Context from the 'input' is added by the calling function below.
      if (!data.success) {
        // Basic error formatting if the operation failed
        return `Error initiating deep research: ${data.message}`;
      }

      // Start building the Markdown output
      const lines: string[] = [
        `## Deep Research Plan Initiated`,
        `**Status:** ${data.message}`, // Display the success message from the core logic
        `**Plan Node ID:** \`${data.planNodeId}\``, // Show the ID of the created root node
      ];

      // Add details about the created sub-topic nodes
      if (data.subTopicNodes && data.subTopicNodes.length > 0) {
        lines.push(
          `\n### Sub-Topics Created (${data.subTopicNodes.length})${
            data.tasksCreated ? " (with Tasks)" : ""
          }:`,
        );
        data.subTopicNodes.forEach((node) => {
          const taskInfo = node.taskId
            ? `\n  - **Task ID:** \`${node.taskId}\``
            : "";
          // Basic info available directly from the result data
          lines.push(
            `- **Question:** ${node.question}\n  - **Node ID:** \`${node.nodeId}\`${taskInfo}`,
            // Note: Initial Search Queries are added by the contextual formatter below
          );
        });
      } else {
        lines.push("\nNo sub-topics were specified or created.");
      }

      return lines.join("\n"); // Combine lines into a single Markdown string
    },
  };

/**
 * Creates the final formatted `McpToolResponse` for the `atlas_deep_research` tool.
 * This function takes the raw result from the core logic (`deepResearch`) and the
 * original tool input, then uses a *contextual* formatter to generate the final
 * Markdown output. The contextual formatter enhances the base format by including
 * details from the input (like topic, goal, scope, tags, and search queries).
 *
 * @param rawData - The `DeepResearchResult` object returned by the `deepResearch` function.
 * @param input - The original `AtlasDeepResearchInput` provided to the tool.
 * @returns The final `McpToolResponse` object ready to be sent back to the client.
 */
export function formatDeepResearchResponse(
  rawData: DeepResearchResult,
  input: AtlasDeepResearchInput,
): McpToolResponse {
  // Define a contextual formatter *inside* this function.
  // This allows the formatter's `format` method to access the `input` variable via closure.
  const contextualFormatter: ResponseFormatter<DeepResearchResult> = {
    format: (data: DeepResearchResult): string => {
      // Handle error case first
      if (!data.success) {
        return `Error initiating deep research: ${data.message}`;
      }

      // Start building the Markdown output, including details from the input
      const lines: string[] = [
        `## Deep Research Plan Initiated`,
        `**Topic:** ${input.researchTopic}`, // Include Topic from input
        `**Goal:** ${input.researchGoal}`, // Include Goal from input
      ];
      if (input.scopeDefinition) {
        lines.push(`**Scope:** ${input.scopeDefinition}`); // Include Scope if provided
      }
      lines.push(`**Project ID:** \`${input.projectId}\``); // Include Project ID
      if (input.researchDomain) {
        lines.push(`**Domain:** ${input.researchDomain}`); // Include Domain if provided
      }
      lines.push(`**Status:** ${data.message}`); // Status message from result
      lines.push(`**Plan Node ID:** \`${data.planNodeId}\``); // Root node ID from result
      if (input.initialTags && input.initialTags.length > 0) {
        lines.push(`**Initial Tags:** ${input.initialTags.join(", ")}`); // Include initial tags
      }

      // Add details about sub-topic nodes, including search queries from input
      if (data.subTopicNodes && data.subTopicNodes.length > 0) {
        lines.push(`\n### Sub-Topics Created (${data.subTopicNodes.length}):`);
        data.subTopicNodes.forEach((node) => {
          // Find the corresponding sub-topic in the input to retrieve initial search queries
          // Find the corresponding sub-topic in the input to retrieve initial search queries and task details
          const inputSubTopic = input.subTopics.find(
            (st) => st.question === node.question,
          );
          const searchQueries =
            inputSubTopic?.initialSearchQueries?.join(", ") || "N/A"; // Format queries or show N/A
          const taskInfo = node.taskId
            ? `\n  - **Task ID:** \`${node.taskId}\``
            : ""; // Add Task ID if present
          const priorityInfo = inputSubTopic?.priority
            ? `\n  - **Task Priority:** ${inputSubTopic.priority}`
            : "";
          const assigneeInfo = inputSubTopic?.assignedTo
            ? `\n  - **Task Assignee:** ${inputSubTopic.assignedTo}`
            : "";
          const statusInfo = inputSubTopic?.initialStatus
            ? `\n  - **Task Status:** ${inputSubTopic.initialStatus}`
            : "";

          lines.push(
            `- **Question:** ${node.question}\n  - **Node ID:** \`${node.nodeId}\`${taskInfo}${priorityInfo}${assigneeInfo}${statusInfo}\n  - **Initial Search Queries:** ${searchQueries}`, // Add search queries and task details
          );
        });
      } else {
        lines.push("\nNo sub-topics were specified or created.");
      }

      return lines.join("\n"); // Combine all lines into the final Markdown string
    },
  };

  const formattedText = contextualFormatter.format(rawData);
  return createToolResponse(formattedText, !rawData.success);
}

```

--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/exportLogic.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Implements the database export logic for Neo4j.
 * @module src/services/neo4j/backupRestoreService/exportLogic
 */

import { format } from "date-fns";
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
import { Session } from "neo4j-driver";
import { logger, requestContextService } from "../../../utils/index.js";
import { neo4jDriver } from "../driver.js";
import { FullExport } from "./backupRestoreTypes.js";
import {
  manageBackupRotation,
  secureResolve,
  validatedBackupRoot,
} from "./backupUtils.js";

/**
 * Exports all Project, Task, and Knowledge nodes and relationships to JSON files.
 * Also creates a full-export.json file containing all data in a single file.
 * Manages backup rotation before creating the new backup.
 * @returns The path to the directory containing the backup files.
 * @throws Error if the export step fails. Rotation errors are logged but don't throw.
 */
export const _exportDatabase = async (): Promise<string> => {
  const operationName = "_exportDatabase"; // Renamed
  const baseContext = requestContextService.createRequestContext({
    operation: operationName,
  });

  await manageBackupRotation();

  let session: Session | null = null;
  const timestamp = format(new Date(), "yyyyMMddHHmmss");
  const backupDirName = `atlas-backup-${timestamp}`;

  const backupDir = secureResolve(validatedBackupRoot, backupDirName);
  if (!backupDir) {
    throw new Error(
      `Failed to create secure backup directory path for ${backupDirName} within ${validatedBackupRoot}`,
    );
  }

  const fullExport: FullExport = {
    nodes: {},
    relationships: [],
  };

  try {
    session = await neo4jDriver.getSession();
    logger.info(`Starting database export to ${backupDir}...`, baseContext);

    if (!existsSync(backupDir)) {
      mkdirSync(backupDir, { recursive: true });
      logger.debug(`Created backup directory: ${backupDir}`, baseContext);
    }

    logger.debug("Fetching all node labels from database...", baseContext);
    const labelsResult = await session.run(
      "CALL db.labels() YIELD label RETURN label",
    );
    const nodeLabels: string[] = labelsResult.records.map((record) =>
      record.get("label"),
    );
    logger.info(`Found labels: ${nodeLabels.join(", ")}`, {
      ...baseContext,
      labels: nodeLabels,
    });

    for (const label of nodeLabels) {
      logger.debug(`Exporting nodes with label: ${label}`, {
        ...baseContext,
        currentLabel: label,
      });
      const escapedLabel = `\`${label.replace(/`/g, "``")}\``;
      const nodeResult = await session.run(
        `MATCH (n:${escapedLabel}) RETURN n`,
      );
      const nodes = nodeResult.records.map(
        (record) => record.get("n").properties,
      );

      const fileName = `${label.toLowerCase()}s.json`;
      const filePath = secureResolve(backupDir, fileName);
      if (!filePath) {
        logger.error(
          `Skipping export for label ${label}: Could not create secure path for ${fileName} in ${backupDir}`,
          new Error("Secure path resolution failed"),
          { ...baseContext, label, fileName, targetDir: backupDir },
        );
        continue;
      }

      writeFileSync(filePath, JSON.stringify(nodes, null, 2));
      logger.info(
        `Successfully exported ${nodes.length} ${label} nodes to ${filePath}`,
        { ...baseContext, label, count: nodes.length, filePath },
      );
      fullExport.nodes[label] = nodes;
    }

    logger.debug("Exporting relationships...", baseContext);
    const relResult = await session.run(`
      MATCH (start)-[r]->(end)
      WHERE start.id IS NOT NULL AND end.id IS NOT NULL
      RETURN 
        start.id as startNodeAppId, 
        end.id as endNodeAppId, 
        type(r) as relType, 
        properties(r) as relProps
    `);
    const relationships = relResult.records.map((record) => ({
      startNodeId: record.get("startNodeAppId"),
      endNodeId: record.get("endNodeAppId"),
      type: record.get("relType"),
      properties: record.get("relProps") || {},
    }));

    const relFileName = "relationships.json";
    const relFilePath = secureResolve(backupDir, relFileName);
    if (!relFilePath) {
      throw new Error(
        `Failed to create secure path for ${relFileName} in ${backupDir}`,
      );
    }
    writeFileSync(relFilePath, JSON.stringify(relationships, null, 2));
    logger.info(
      `Successfully exported ${relationships.length} relationships to ${relFilePath}`,
      { ...baseContext, count: relationships.length, filePath: relFilePath },
    );
    fullExport.relationships = relationships;

    const fullExportFileName = "full-export.json";
    const fullExportPath = secureResolve(backupDir, fullExportFileName);
    if (!fullExportPath) {
      throw new Error(
        `Failed to create secure path for ${fullExportFileName} in ${backupDir}`,
      );
    }
    writeFileSync(fullExportPath, JSON.stringify(fullExport, null, 2));
    logger.info(
      `Successfully created full database export to ${fullExportPath}`,
      { ...baseContext, filePath: fullExportPath },
    );

    logger.info(
      `Database export completed successfully to ${backupDir}`,
      baseContext,
    );
    return backupDir;
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    logger.error(
      `Database export failed: ${errorMessage}`,
      error as Error,
      baseContext,
    );
    if (backupDir && existsSync(backupDir)) {
      if (!backupDir.startsWith(validatedBackupRoot + require("path").sep)) {
        // Use require("path") for sep
        logger.error(
          `Security Error: Attempting cleanup of directory outside backup root: ${backupDir}. Aborting cleanup.`,
          new Error("Cleanup security violation"),
          { ...baseContext, cleanupDir: backupDir },
        );
      } else {
        try {
          rmSync(backupDir, { recursive: true, force: true });
          logger.warning(
            `Removed partially created backup directory due to export failure: ${backupDir}`,
            { ...baseContext, cleanupDir: backupDir },
          );
        } catch (rmError) {
          const rmErrorMsg =
            rmError instanceof Error ? rmError.message : String(rmError);
          logger.error(
            `Failed to remove partial backup directory ${backupDir}: ${rmErrorMsg}`,
            rmError as Error,
            { ...baseContext, cleanupDir: backupDir },
          );
        }
      }
    }
    throw new Error(`Database export failed: ${errorMessage}`);
  } finally {
    if (session) {
      await session.close();
    }
  }
};

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_update/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import {
  TaskResponse,
  McpToolResponse,
  createToolResponse,
} from "../../../types/mcp.js";

/**
 * Extends the TaskResponse to include Neo4j properties structure
 */
interface SingleTaskResponse extends TaskResponse {
  properties?: any;
  identity?: number;
  labels?: string[];
  elementId?: string;
}

/**
 * Interface for bulk task update response
 */
interface BulkTaskResponse {
  success: boolean;
  message: string;
  updated: (TaskResponse & {
    properties?: any;
    identity?: number;
    labels?: string[];
    elementId?: string;
  })[];
  errors: {
    index: number;
    task: {
      id: string;
      updates: any;
    };
    error: {
      code: string;
      message: string;
      details?: any;
    };
  }[];
}

/**
 * Formatter for individual task update responses
 */
class SingleTaskUpdateFormatter {
  format(data: SingleTaskResponse): string {
    // Extract task properties from Neo4j structure
    const taskData = data.properties || data;
    const { title, id, projectId, status, priority, taskType, updatedAt } =
      taskData;

    // Create a structured summary section
    const summary =
      `Task Updated Successfully\n\n` +
      `Task: ${title || "Unnamed Task"}\n` +
      `ID: ${id || "Unknown ID"}\n` +
      `Project ID: ${projectId || "Unknown Project"}\n` +
      `Status: ${status || "Unknown Status"}\n` +
      `Priority: ${priority || "Unknown Priority"}\n` +
      `Type: ${taskType || "Unknown Type"}\n` +
      `Updated: ${updatedAt ? new Date(updatedAt).toLocaleString() : "Unknown Date"}\n`;

    // Create a comprehensive details section with all task attributes
    let details = `Task Details\n\n`;

    // Add each property with proper formatting
    if (taskData.id) details += `ID: ${taskData.id}\n`;
    if (taskData.projectId) details += `Project ID: ${taskData.projectId}\n`;
    if (taskData.title) details += `Title: ${taskData.title}\n`;
    if (taskData.description)
      details += `Description: ${taskData.description}\n`;
    if (taskData.priority) details += `Priority: ${taskData.priority}\n`;
    if (taskData.status) details += `Status: ${taskData.status}\n`;
    if (taskData.assignedTo) details += `Assigned To: ${taskData.assignedTo}\n`;

    // Format URLs array
    if (taskData.urls) {
      const urlsValue =
        Array.isArray(taskData.urls) && taskData.urls.length > 0
          ? JSON.stringify(taskData.urls)
          : "None";
      details += `URLs: ${urlsValue}\n`;
    }

    // Format tags array
    if (taskData.tags) {
      const tagsValue =
        Array.isArray(taskData.tags) && taskData.tags.length > 0
          ? taskData.tags.join(", ")
          : "None";
      details += `Tags: ${tagsValue}\n`;
    }

    if (taskData.completionRequirements)
      details += `Completion Requirements: ${taskData.completionRequirements}\n`;
    if (taskData.outputFormat)
      details += `Output Format: ${taskData.outputFormat}\n`;
    if (taskData.taskType) details += `Task Type: ${taskData.taskType}\n`;

    // Format dates
    if (taskData.createdAt) {
      const createdDate =
        typeof taskData.createdAt === "string" &&
        /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(taskData.createdAt)
          ? new Date(taskData.createdAt).toLocaleString()
          : taskData.createdAt;
      details += `Created At: ${createdDate}\n`;
    }

    if (taskData.updatedAt) {
      const updatedDate =
        typeof taskData.updatedAt === "string" &&
        /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(taskData.updatedAt)
          ? new Date(taskData.updatedAt).toLocaleString()
          : taskData.updatedAt;
      details += `Updated At: ${updatedDate}\n`;
    }

    return `${summary}\n\n${details}`;
  }
}

/**
 * Formatter for bulk task update responses
 */
class BulkTaskUpdateFormatter {
  format(data: BulkTaskResponse): string {
    const { success, message, updated, errors } = data;

    // Create a summary section
    const summary =
      `${success ? "Tasks Updated Successfully" : "Task Updates Completed with Errors"}\n\n` +
      `Status: ${success ? "✅ Success" : "⚠️ Partial Success"}\n` +
      `Summary: ${message}\n` +
      `Updated: ${updated.length} task(s)\n` +
      `Errors: ${errors.length} error(s)\n`;

    // List all successfully modified tasks
    let updatedSection = "";
    if (updated.length > 0) {
      updatedSection = `Updated Tasks\n\n`;

      updatedSection += updated
        .map((task, index) => {
          // Extract task properties from Neo4j structure
          const taskData = task.properties || task;
          return (
            `${index + 1}. ${taskData.title || "Unnamed Task"}\n\n` +
            `ID: ${taskData.id || "Unknown ID"}\n` +
            `Project ID: ${taskData.projectId || "Unknown Project"}\n` +
            `Type: ${taskData.taskType || "Unknown Type"}\n` +
            `Status: ${taskData.status || "Unknown Status"}\n` +
            `Priority: ${taskData.priority || "Unknown Priority"}\n` +
            `Updated: ${taskData.updatedAt ? new Date(taskData.updatedAt).toLocaleString() : "Unknown Date"}\n`
          );
        })
        .join("\n\n");
    }

    // List any errors that occurred
    let errorsSection = "";
    if (errors.length > 0) {
      errorsSection = `Errors\n\n`;

      errorsSection += errors
        .map((error, index) => {
          return (
            `${index + 1}. Error updating Task ID: "${error.task.id}"\n\n` +
            `Error Code: ${error.error.code}\n` +
            `Message: ${error.error.message}\n` +
            (error.error.details
              ? `Details: ${JSON.stringify(error.error.details)}\n`
              : "")
          );
        })
        .join("\n\n");
    }

    return `${summary}\n\n${updatedSection}\n\n${errorsSection}`.trim();
  }
}

/**
 * Create a formatted, human-readable response for the atlas_task_update tool
 *
 * @param data The raw task update response
 * @param isError Whether this response represents an error condition
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatTaskUpdateResponse(
  data: any,
  isError = false,
): McpToolResponse {
  // Determine if this is a single or bulk task response
  const isBulkResponse =
    data.hasOwnProperty("success") && data.hasOwnProperty("updated");

  let formattedText: string;
  if (isBulkResponse) {
    const formatter = new BulkTaskUpdateFormatter();
    formattedText = formatter.format(data as BulkTaskResponse);
  } else {
    const formatter = new SingleTaskUpdateFormatter();
    formattedText = formatter.format(data as SingleTaskResponse);
  }
  return createToolResponse(formattedText, isError);
}

```

--------------------------------------------------------------------------------
/src/webui/styling/layout.css:
--------------------------------------------------------------------------------

```css
/* ==========================================================================
   Main Application Layout (#app, header, main, footer)
   ========================================================================== */
#app {
  position: relative; /* For theme toggle positioning */
  max-width: 1000px;
  margin: var(--spacing-xl) auto;
  padding: var(--spacing-lg) var(--spacing-xl);
  background-color: var(--card-bg-color);
  border-radius: var(--border-radius-lg);
  box-shadow: 0 8px 24px var(--shadow-color);
  transition: background-color 0.2s ease-out;
}

.app-header {
  margin-bottom: var(--spacing-xl);
}

.app-footer {
  margin-top: var(--spacing-xl);
  padding-top: var(--spacing-lg);
  border-top: 1px solid var(--border-color);
}

/* ==========================================================================
   Controls Section (Project Select, Refresh Button)
   ========================================================================== */
.controls-section {
  margin-bottom: var(--spacing-xl);
}
.controls-container {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex-wrap: wrap;
}

.controls-container label {
  margin-bottom: 0; /* Align with controls */
  flex-shrink: 0; /* Prevent label from shrinking */
}

/* ==========================================================================
   Data Sections (Project Details, Tasks, Knowledge)
   ========================================================================== */
.data-section {
  margin-top: var(--spacing-xl);
  padding: var(--spacing-lg);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  background-color: var(--data-section-bg);
  transition:
    background-color 0.2s ease-out,
    border-color 0.2s ease-out;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--spacing-md);
  flex-wrap: wrap; /* Allow wrapping for view controls */
  gap: var(--spacing-md);
}

.section-header h3 {
  margin-bottom: 0; /* Remove bottom margin as it's handled by section-header */
}

/* Project Details Grid Specifics */
#details-content.details-grid {
  display: grid;
  grid-template-columns: auto 1fr; /* Label and value */
  gap: var(--spacing-sm) var(--spacing-md);
  align-items: start; /* Align items to the start of their grid cell */
}

#details-content.details-grid > .data-item {
  display: contents; /* Allow children (strong, div/pre/ul) to participate in the grid */
}

#details-content.details-grid > .data-item > strong {
  /* Label */
  font-weight: 500;
  color: var(--secondary-text-color);
  padding-top: var(--spacing-xs); /* Align with multi-line values better */
  grid-column: 1;
}
#details-content.details-grid > .data-item > div,
#details-content.details-grid > .data-item > pre,
#details-content.details-grid > .data-item > ul {
  /* Value */
  grid-column: 2;
  margin-bottom: 0; /* Remove default margin from these elements when in grid */
}
#details-content.details-grid > .data-item > ul {
  list-style-position: outside; /* More standard list appearance */
  padding-left: var(--spacing-md); /* Indent list items */
  margin-top: 0;
}
#details-content.details-grid > .data-item > ul li {
  margin-bottom: var(--spacing-xs);
}

/* General Data Items (Used for Tasks, Knowledge in non-grid layout) */
.data-item {
  padding-bottom: var(--spacing-md);
  margin-bottom: var(--spacing-md);
  border-bottom: 1px solid var(--data-item-border-color);
  transition: border-color 0.2s ease-out;
}

.data-item:last-child {
  border-bottom: none;
  margin-bottom: 0;
  padding-bottom: 0;
}

.data-item strong {
  /* Used in task/knowledge titles */
  color: var(--text-color);
  font-weight: 600;
  display: block; /* Make title take full width */
  margin-bottom: var(--spacing-xs);
}

.data-item div {
  /* General content div within a data item */
  margin-bottom: var(--spacing-xs);
}

/* ==========================================================================
   Mermaid Diagram Container
   ========================================================================== */
.mermaid-container {
  width: 100%;
  min-height: 300px; /* Adjust as needed */
  overflow: auto; /* For larger diagrams */
  margin-top: var(--spacing-md);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  padding: var(--spacing-md);
  background-color: var(
    --card-bg-color
  ); /* Match card background for consistency */
  box-sizing: border-box; /* Ensure padding and border are included in width/height */
}
.mermaid-container svg {
  display: block; /* Remove extra space below SVG */
  margin: auto; /* Center if smaller than container */
  max-width: 100%; /* Ensure SVG scales down if too wide */
}

/* ==========================================================================
   Task Board Styles
   ========================================================================== */
.task-board-grid {
  display: flex;
  gap: var(--spacing-md);
  overflow-x: auto; /* Allow horizontal scrolling for columns */
  padding-bottom: var(--spacing-md); /* Space for scrollbar */
  min-height: 300px; /* Ensure columns have some height */
}

.task-board-column {
  flex: 0 0 280px; /* Fixed width for columns, adjust as needed */
  max-width: 280px;
  background-color: var(
    --bg-color
  ); /* Slightly different from card for distinction */
  border-radius: var(--border-radius-md);
  padding: var(--spacing-md);
  border: 1px solid var(--border-color);
  display: flex;
  flex-direction: column;
  transition: background-color 0.2s ease-out;
}

.task-board-column h4 {
  font-size: 1.1rem;
  font-weight: 600;
  margin-bottom: var(--spacing-md);
  padding-bottom: var(--spacing-sm);
  border-bottom: 1px solid var(--border-color);
  text-align: center;
}

.task-board-column-content {
  flex-grow: 1;
  overflow-y: auto; /* Allow scrolling within a column if many tasks */
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

/* ==========================================================================
   Data Explorer Styles
   ========================================================================== */
#data-explorer-container .controls-container {
  margin-bottom: var(--spacing-lg); /* Space between controls and content */
}

.explorer-node-list {
  max-height: 400px; /* Limit height and allow scrolling */
  overflow-y: auto;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  padding: var(--spacing-sm);
  margin-bottom: var(--spacing-lg); /* Space before details section */
}

#data-explorer-details {
  /* Uses .details-grid, so existing styles apply. 
     Can add specific overrides if needed */
  margin-top: var(--spacing-lg);
  padding-top: var(--spacing-lg);
  border-top: 1px solid var(--border-color);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_update/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { ProjectResponse } from "../../../types/mcp.js";
import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator

/**
 * Defines a generic interface for formatting data into a string.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Extends the ProjectResponse to include Neo4j properties structure
 */
interface SingleProjectResponse extends ProjectResponse {
  properties?: any;
  identity?: number;
  labels?: string[];
  elementId?: string;
}

/**
 * Interface for bulk project update response
 */
interface BulkProjectResponse {
  success: boolean;
  message: string;
  updated: (ProjectResponse & {
    properties?: any;
    identity?: number;
    labels?: string[];
    elementId?: string;
  })[];
  errors: {
    index: number;
    project: {
      // Original input for the failed update
      id: string;
      updates: any;
    };
    error: {
      code: string;
      message: string;
      details?: any;
    };
  }[];
}

/**
 * Formatter for individual project modification responses
 */
export class SingleProjectUpdateFormatter
  implements ResponseFormatter<SingleProjectResponse>
{
  format(data: SingleProjectResponse): string {
    // Extract project properties from Neo4j structure or direct data
    const projectData = data.properties || data;
    const {
      name,
      id,
      status,
      taskType,
      updatedAt,
      description,
      urls,
      completionRequirements,
      outputFormat,
      createdAt,
    } = projectData;

    // Create a structured summary section
    const summary =
      `Project Modified Successfully\n\n` +
      `Project: ${name || "Unnamed Project"}\n` +
      `ID: ${id || "Unknown ID"}\n` +
      `Status: ${status || "Unknown Status"}\n` +
      `Type: ${taskType || "Unknown Type"}\n` +
      `Updated: ${updatedAt ? new Date(updatedAt).toLocaleString() : "Unknown Date"}\n`;

    // Create a comprehensive details section
    let details = `Project Details:\n`;
    const fieldLabels: Record<keyof SingleProjectResponse, string> = {
      id: "ID",
      name: "Name",
      description: "Description",
      status: "Status",
      urls: "URLs",
      completionRequirements: "Completion Requirements",
      outputFormat: "Output Format",
      taskType: "Task Type",
      createdAt: "Created At",
      updatedAt: "Updated At",
      properties: "Raw Properties",
      identity: "Neo4j Identity",
      labels: "Neo4j Labels",
      elementId: "Neo4j Element ID",
      dependencies: "Dependencies",
    };
    const relevantKeys: (keyof SingleProjectResponse)[] = [
      "id",
      "name",
      "description",
      "status",
      "taskType",
      "completionRequirements",
      "outputFormat",
      "urls",
      "createdAt",
      "updatedAt",
    ];

    relevantKeys.forEach((key) => {
      if (projectData[key] !== undefined && projectData[key] !== null) {
        let value = projectData[key];
        if (Array.isArray(value)) {
          value =
            value.length > 0
              ? value
                  .map((item) =>
                    typeof item === "object" ? JSON.stringify(item) : item,
                  )
                  .join(", ")
              : "None";
        } else if (
          typeof value === "string" &&
          (key === "createdAt" || key === "updatedAt")
        ) {
          try {
            value = new Date(value).toLocaleString();
          } catch (e) {
            /* Keep original */
          }
        }
        details += `  ${fieldLabels[key] || key}: ${value}\n`;
      }
    });

    return `${summary}\n${details}`;
  }
}

/**
 * Formatter for bulk project update responses
 */
export class BulkProjectUpdateFormatter
  implements ResponseFormatter<BulkProjectResponse>
{
  format(data: BulkProjectResponse): string {
    const { success, message, updated, errors } = data;

    const summary =
      `${success && errors.length === 0 ? "Projects Updated Successfully" : "Project Updates Completed"}\n\n` +
      `Status: ${success && errors.length === 0 ? "✅ Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
      `Summary: ${message}\n` +
      `Updated: ${updated.length} project(s)\n` +
      `Errors: ${errors.length} error(s)\n`;

    let updatedSection = "";
    if (updated.length > 0) {
      updatedSection = `\n--- Modified Projects (${updated.length}) ---\n\n`;
      updatedSection += updated
        .map((project, index) => {
          const projectData = project.properties || project;
          return (
            `${index + 1}. ${projectData.name || "Unnamed Project"} (ID: ${projectData.id || "N/A"})\n` +
            `   Status: ${projectData.status || "N/A"}\n` +
            `   Updated: ${projectData.updatedAt ? new Date(projectData.updatedAt).toLocaleString() : "N/A"}`
          );
        })
        .join("\n\n");
    }

    let errorsSection = "";
    if (errors.length > 0) {
      errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
      errorsSection += errors
        .map((errorItem, index) => {
          return (
            `${index + 1}. Error updating Project ID: "${errorItem.project.id}"\n` +
            `   Error Code: ${errorItem.error.code}\n` +
            `   Message: ${errorItem.error.message}` +
            (errorItem.error.details
              ? `\n   Details: ${JSON.stringify(errorItem.error.details)}`
              : "")
          );
        })
        .join("\n\n");
    }

    return `${summary}${updatedSection}${errorsSection}`.trim();
  }
}

/**
 * Create a formatted, human-readable response for the atlas_project_update tool
 *
 * @param data The raw project modification response (SingleProjectResponse or BulkProjectResponse)
 * @param isError Whether this response represents an error condition (primarily for single responses)
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatProjectUpdateResponse(data: any, isError = false): any {
  const isBulkResponse =
    data.hasOwnProperty("success") &&
    data.hasOwnProperty("updated") &&
    data.hasOwnProperty("errors");

  let formattedText: string;
  let finalIsError: boolean;

  if (isBulkResponse) {
    const formatter = new BulkProjectUpdateFormatter();
    const bulkData = data as BulkProjectResponse;
    formattedText = formatter.format(bulkData);
    finalIsError = !bulkData.success || bulkData.errors.length > 0;
  } else {
    const formatter = new SingleProjectUpdateFormatter();
    // For single response, 'data' is the updated project object.
    // 'isError' must be determined by the caller if an error occurred before this point.
    formattedText = formatter.format(data as SingleProjectResponse);
    finalIsError = isError;
  }
  return createToolResponse(formattedText, finalIsError);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_update/types.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";
import {
  McpToolResponse,
  PriorityLevel,
  ResponseFormat,
  TaskStatus,
  TaskType,
  createPriorityLevelEnum,
  createResponseFormatEnum,
  createTaskStatusEnum,
  createTaskTypeEnum,
} from "../../../types/mcp.js";

export const TaskUpdateSchema = z.object({
  id: z.string().describe("Identifier of the existing task to be modified"),
  updates: z
    .object({
      title: z
        .string()
        .min(5)
        .max(150)
        .optional()
        .describe("Modified task title (5-150 characters)"),
      description: z
        .string()
        .optional()
        .describe("Revised task description and requirements"),
      priority: createPriorityLevelEnum()
        .optional()
        .describe("Updated priority level reflecting current importance"),
      status: createTaskStatusEnum()
        .optional()
        .describe("Updated task status reflecting current progress"),
      assignedTo: z.string().nullable().optional().describe(
        // Allow null for unassignment
        "Updated assignee ID for task responsibility (null to unassign)",
      ),
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional()
        .describe("Modified reference materials and documentation links"),
      tags: z
        .array(z.string())
        .optional()
        .describe("Updated categorical labels for task organization"),
      completionRequirements: z
        .string()
        .optional()
        .describe("Revised success criteria for task completion"),
      outputFormat: z
        .string()
        .optional()
        .describe("Modified deliverable specification for task output"),
      taskType: createTaskTypeEnum()
        .optional()
        .describe("Revised classification for task categorization"),
    })
    .describe(
      "Partial update object containing only fields that need modification",
    ),
});

const SingleTaskUpdateSchema = z
  .object({
    mode: z.literal("single"),
    id: z.string(),
    updates: z.object({
      title: z.string().min(5).max(150).optional(),
      description: z.string().optional(),
      priority: createPriorityLevelEnum().optional(),
      status: createTaskStatusEnum().optional(),
      assignedTo: z.string().nullable().optional(), // Allow null
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional(),
      tags: z.array(z.string()).optional(),
      completionRequirements: z.string().optional(),
      outputFormat: z.string().optional(),
      taskType: createTaskTypeEnum().optional(),
    }),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe("Update an individual task with selective field modifications");

const BulkTaskUpdateSchema = z
  .object({
    mode: z.literal("bulk"),
    tasks: z
      .array(
        z.object({
          id: z.string().describe("Identifier of the task to update"),
          updates: z.object({
            title: z.string().min(5).max(150).optional(),
            description: z.string().optional(),
            priority: createPriorityLevelEnum().optional(),
            status: createTaskStatusEnum().optional(),
            assignedTo: z.string().nullable().optional(), // Allow null
            urls: z
              .array(
                z.object({
                  title: z.string(),
                  url: z.string(),
                }),
              )
              .optional(),
            tags: z.array(z.string()).optional(),
            completionRequirements: z.string().optional(),
            outputFormat: z.string().optional(),
            taskType: createTaskTypeEnum().optional(),
          }),
        }),
      )
      .min(1)
      .max(100)
      .describe(
        "Collection of task updates to be applied in a single transaction",
      ),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe("Update multiple related tasks in a single efficient transaction");

// Schema shapes for tool registration
export const AtlasTaskUpdateSchemaShape = {
  mode: z
    .enum(["single", "bulk"])
    .describe(
      "Operation mode - 'single' for one task, 'bulk' for multiple tasks",
    ),
  id: z
    .string()
    .optional()
    .describe("Existing task ID to update (required for mode='single')"),
  updates: z
    .object({
      title: z.string().min(5).max(150).optional(),
      description: z.string().optional(),
      priority: createPriorityLevelEnum().optional(),
      status: createTaskStatusEnum().optional(),
      assignedTo: z.string().nullable().optional(), // Allow null
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional(),
      tags: z.array(z.string()).optional(),
      completionRequirements: z.string().optional(),
      outputFormat: z.string().optional(),
      taskType: createTaskTypeEnum().optional(),
    })
    .optional()
    .describe(
      "Object containing fields to modify (only specified fields will be updated) (required for mode='single')",
    ),
  tasks: z
    .array(
      z.object({
        id: z.string(),
        updates: z.object({
          title: z.string().min(5).max(150).optional(),
          description: z.string().optional(),
          priority: createPriorityLevelEnum().optional(),
          status: createTaskStatusEnum().optional(),
          assignedTo: z.string().nullable().optional(), // Allow null
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .optional(),
          tags: z.array(z.string()).optional(),
          completionRequirements: z.string().optional(),
          outputFormat: z.string().optional(),
          taskType: createTaskTypeEnum().optional(),
        }),
      }),
    )
    .optional()
    .describe(
      "Array of task updates, each containing an ID and updates object (required for mode='bulk')",
    ),
  responseFormat: createResponseFormatEnum()
    .optional()
    .describe(
      "Desired response format: 'formatted' (default string) or 'json' (raw object)",
    ),
} as const;

// Schema for validation
export const AtlasTaskUpdateSchema = z.discriminatedUnion("mode", [
  SingleTaskUpdateSchema,
  BulkTaskUpdateSchema,
]);

export type AtlasTaskUpdateInput = z.infer<typeof AtlasTaskUpdateSchema>;
export type TaskUpdateInput = z.infer<typeof TaskUpdateSchema>;
export type AtlasTaskUpdateResponse = McpToolResponse;

```

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

```typescript
/**
 * @fileoverview Provides a generic `RateLimiter` class for implementing rate limiting logic.
 * It supports configurable time windows, request limits, and automatic cleanup of expired entries.
 * @module src/utils/security/rateLimiter
 */
import { environment } from "../../config/index.js";
import { BaseErrorCode, McpError } from "../../types/errors.js";
import { logger, RequestContext, requestContextService } from "../index.js";

/**
 * Defines configuration options for the {@link RateLimiter}.
 */
export interface RateLimitConfig {
  /** Time window in milliseconds. */
  windowMs: number;
  /** Maximum number of requests allowed in the window. */
  maxRequests: number;
  /** Custom error message template. Can include `{waitTime}` placeholder. */
  errorMessage?: string;
  /** If true, skip rate limiting in development. */
  skipInDevelopment?: boolean;
  /** Optional function to generate a custom key for rate limiting. */
  keyGenerator?: (identifier: string, context?: RequestContext) => string;
  /** How often, in milliseconds, to clean up expired entries. */
  cleanupInterval?: number;
}

/**
 * Represents an individual entry for tracking requests against a rate limit key.
 */
export interface RateLimitEntry {
  /** Current request count. */
  count: number;
  /** When the window resets (timestamp in milliseconds). */
  resetTime: number;
}

/**
 * A generic rate limiter class using an in-memory store.
 * Controls frequency of operations based on unique keys.
 */
export class RateLimiter {
  /**
   * Stores current request counts and reset times for each key.
   * @private
   */
  private limits: Map<string, RateLimitEntry>;
  /**
   * Timer ID for periodic cleanup.
   * @private
   */
  private cleanupTimer: NodeJS.Timeout | null = null;

  /**
   * Default configuration values.
   * @private
   */
  private static DEFAULT_CONFIG: RateLimitConfig = {
    windowMs: 15 * 60 * 1000, // 15 minutes
    maxRequests: 100,
    errorMessage:
      "Rate limit exceeded. Please try again in {waitTime} seconds.",
    skipInDevelopment: false,
    cleanupInterval: 5 * 60 * 1000, // 5 minutes
  };

  /**
   * Creates a new `RateLimiter` instance.
   * @param config - Configuration options, merged with defaults.
   */
  constructor(private config: RateLimitConfig) {
    this.config = { ...RateLimiter.DEFAULT_CONFIG, ...config };
    this.limits = new Map();
    this.startCleanupTimer();
  }

  /**
   * Starts the periodic timer to clean up expired rate limit entries.
   * @private
   */
  private startCleanupTimer(): void {
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
    }

    const interval =
      this.config.cleanupInterval ?? RateLimiter.DEFAULT_CONFIG.cleanupInterval;

    if (interval && interval > 0) {
      this.cleanupTimer = setInterval(() => {
        this.cleanupExpiredEntries();
      }, interval);

      if (this.cleanupTimer.unref) {
        this.cleanupTimer.unref(); // Allow Node.js process to exit if only timer active
      }
    }
  }

  /**
   * Removes expired rate limit entries from the store.
   * @private
   */
  private cleanupExpiredEntries(): void {
    const now = Date.now();
    let expiredCount = 0;

    for (const [key, entry] of this.limits.entries()) {
      if (now >= entry.resetTime) {
        this.limits.delete(key);
        expiredCount++;
      }
    }

    if (expiredCount > 0) {
      const logContext = requestContextService.createRequestContext({
        operation: "RateLimiter.cleanupExpiredEntries",
        cleanedCount: expiredCount,
        totalRemainingAfterClean: this.limits.size,
      });
      logger.debug(
        `Cleaned up ${expiredCount} expired rate limit entries`,
        logContext,
      );
    }
  }

  /**
   * Updates the configuration of the rate limiter instance.
   * @param config - New configuration options to merge.
   */
  public configure(config: Partial<RateLimitConfig>): void {
    this.config = { ...this.config, ...config };
    if (config.cleanupInterval !== undefined) {
      this.startCleanupTimer();
    }
  }

  /**
   * Retrieves a copy of the current rate limiter configuration.
   * @returns The current configuration.
   */
  public getConfig(): RateLimitConfig {
    return { ...this.config };
  }

  /**
   * Resets all rate limits by clearing the internal store.
   */
  public reset(): void {
    this.limits.clear();
    const logContext = requestContextService.createRequestContext({
      operation: "RateLimiter.reset",
    });
    logger.debug("Rate limiter reset, all limits cleared", logContext);
  }

  /**
   * Checks if a request exceeds the configured rate limit.
   * Throws an `McpError` if the limit is exceeded.
   *
   * @param key - A unique identifier for the request source.
   * @param context - Optional request context for custom key generation.
   * @throws {McpError} If the rate limit is exceeded.
   */
  public check(key: string, context?: RequestContext): void {
    if (this.config.skipInDevelopment && environment === "development") {
      return;
    }

    const limitKey = this.config.keyGenerator
      ? this.config.keyGenerator(key, context)
      : key;

    const now = Date.now();
    const entry = this.limits.get(limitKey);

    if (!entry || now >= entry.resetTime) {
      this.limits.set(limitKey, {
        count: 1,
        resetTime: now + this.config.windowMs,
      });
      return;
    }

    if (entry.count >= this.config.maxRequests) {
      const waitTime = Math.ceil((entry.resetTime - now) / 1000);
      const errorMessage = (
        this.config.errorMessage || RateLimiter.DEFAULT_CONFIG.errorMessage!
      ).replace("{waitTime}", waitTime.toString());

      throw new McpError(BaseErrorCode.RATE_LIMITED, errorMessage, {
        waitTimeSeconds: waitTime,
        key: limitKey,
        limit: this.config.maxRequests,
        windowMs: this.config.windowMs,
      });
    }

    entry.count++;
  }

  /**
   * Retrieves the current rate limit status for a specific key.
   * @param key - The rate limit key.
   * @returns Status object or `null` if no entry exists.
   */
  public getStatus(key: string): {
    current: number;
    limit: number;
    remaining: number;
    resetTime: number;
  } | null {
    const entry = this.limits.get(key);
    if (!entry) {
      return null;
    }
    return {
      current: entry.count,
      limit: this.config.maxRequests,
      remaining: Math.max(0, this.config.maxRequests - entry.count),
      resetTime: entry.resetTime,
    };
  }

  /**
   * Stops the cleanup timer and clears all rate limit entries.
   * Call when the rate limiter is no longer needed.
   */
  public dispose(): void {
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
      this.cleanupTimer = null;
    }
    this.limits.clear();
  }
}

/**
 * Default singleton instance of the `RateLimiter`.
 * Initialized with default configuration. Use `rateLimiter.configure({})` to customize.
 */
export const rateLimiter = new RateLimiter({
  windowMs: 15 * 60 * 1000, // Default: 15 minutes
  maxRequests: 100, // Default: 100 requests per window
});

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_add/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator

/**
 * Defines a generic interface for formatting data into a string.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Interface for a single knowledge item response
 */
interface SingleKnowledgeResponse {
  id: string;
  projectId: string;
  text: string;
  tags?: string[];
  domain: string;
  citations?: string[];
  createdAt: string;
  updatedAt: string;
  properties?: any; // Neo4j properties if not fully mapped
  identity?: number; // Neo4j internal ID
  labels?: string[]; // Neo4j labels
  elementId?: string; // Neo4j element ID
}

/**
 * Interface for bulk knowledge addition response
 */
interface BulkKnowledgeResponse {
  success: boolean;
  message: string;
  created: (SingleKnowledgeResponse & {
    properties?: any;
    identity?: number;
    labels?: string[];
    elementId?: string;
  })[];
  errors: {
    index: number;
    knowledge: any; // Original input for the failed item
    error: {
      code: string;
      message: string;
      details?: any;
    };
  }[];
}

/**
 * Formatter for single knowledge item addition responses
 */
export class SingleKnowledgeFormatter
  implements ResponseFormatter<SingleKnowledgeResponse>
{
  format(data: SingleKnowledgeResponse): string {
    // Extract knowledge properties from Neo4j structure or direct data
    const knowledgeData = data.properties || data;
    const {
      id,
      projectId,
      domain,
      createdAt,
      text,
      tags,
      citations,
      updatedAt,
    } = knowledgeData;

    // Create a summary section
    const summary =
      `Knowledge Item Added Successfully\n\n` +
      `ID: ${id || "Unknown ID"}\n` +
      `Project ID: ${projectId || "Unknown Project"}\n` +
      `Domain: ${domain || "Uncategorized"}\n` +
      `Created: ${createdAt ? new Date(createdAt).toLocaleString() : "Unknown Date"}\n`;

    // Create a comprehensive details section
    const fieldLabels: Record<keyof SingleKnowledgeResponse, string> = {
      id: "ID",
      projectId: "Project ID",
      text: "Content",
      tags: "Tags",
      domain: "Domain",
      citations: "Citations",
      createdAt: "Created At",
      updatedAt: "Updated At",
      // Neo4j specific fields are generally not for direct user display unless needed
      properties: "Raw Properties",
      identity: "Neo4j Identity",
      labels: "Neo4j Labels",
      elementId: "Neo4j Element ID",
    };

    let details = `Knowledge Item Details\n\n`;

    // Build details as key-value pairs for relevant fields
    (Object.keys(fieldLabels) as Array<keyof SingleKnowledgeResponse>).forEach(
      (key) => {
        if (
          knowledgeData[key] !== undefined &&
          ["properties", "identity", "labels", "elementId"].indexOf(
            key as string,
          ) === -1
        ) {
          // Exclude raw Neo4j fields from default display
          let value = knowledgeData[key];

          if (Array.isArray(value)) {
            value = value.length > 0 ? value.join(", ") : "None";
          } else if (
            typeof value === "string" &&
            (key === "createdAt" || key === "updatedAt")
          ) {
            try {
              value = new Date(value).toLocaleString();
            } catch (e) {
              /* Keep original if parsing fails */
            }
          }

          if (
            key === "text" &&
            typeof value === "string" &&
            value.length > 100
          ) {
            value = value.substring(0, 100) + "... (truncated)";
          }

          details += `${fieldLabels[key]}: ${value}\n`;
        }
      },
    );

    return `${summary}\n${details}`;
  }
}

/**
 * Formatter for bulk knowledge addition responses
 */
export class BulkKnowledgeFormatter
  implements ResponseFormatter<BulkKnowledgeResponse>
{
  format(data: BulkKnowledgeResponse): string {
    const { success, message, created, errors } = data;

    const summary =
      `${success && errors.length === 0 ? "Knowledge Items Added Successfully" : "Knowledge Addition Completed"}\n\n` +
      `Status: ${success && errors.length === 0 ? "✅ Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
      `Summary: ${message}\n` +
      `Added: ${created.length} item(s)\n` +
      `Errors: ${errors.length} error(s)\n`;

    let createdSection = "";
    if (created.length > 0) {
      createdSection = `\n--- Added Knowledge Items (${created.length}) ---\n\n`;
      createdSection += created
        .map((item, index) => {
          const itemData = item.properties || item;
          return (
            `${index + 1}. ID: ${itemData.id || "N/A"}\n` +
            `   Project ID: ${itemData.projectId || "N/A"}\n` +
            `   Domain: ${itemData.domain || "N/A"}\n` +
            `   Tags: ${itemData.tags ? itemData.tags.join(", ") : "None"}\n` +
            `   Created: ${itemData.createdAt ? new Date(itemData.createdAt).toLocaleString() : "N/A"}`
          );
        })
        .join("\n\n");
    }

    let errorsSection = "";
    if (errors.length > 0) {
      errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
      errorsSection += errors
        .map((errorDetail, index) => {
          const itemInput = errorDetail.knowledge;
          return (
            `${index + 1}. Error for item (Index: ${errorDetail.index})\n` +
            `   Input Project ID: ${itemInput?.projectId || "N/A"}\n` +
            `   Input Domain: ${itemInput?.domain || "N/A"}\n` +
            `   Error Code: ${errorDetail.error.code}\n` +
            `   Message: ${errorDetail.error.message}` +
            (errorDetail.error.details
              ? `\n   Details: ${JSON.stringify(errorDetail.error.details)}`
              : "")
          );
        })
        .join("\n\n");
    }

    return `${summary}${createdSection}${errorsSection}`.trim();
  }
}

/**
 * Create a formatted, human-readable response for the atlas_knowledge_add tool
 *
 * @param data The raw knowledge addition response data (can be SingleKnowledgeResponse or BulkKnowledgeResponse)
 * @param isError Whether this response represents an error condition (primarily for single responses if not inherent in data)
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatKnowledgeAddResponse(data: any, isError = false): any {
  const isBulkResponse =
    data.hasOwnProperty("success") &&
    data.hasOwnProperty("created") &&
    data.hasOwnProperty("errors");

  let formattedText: string;
  let finalIsError: boolean;

  if (isBulkResponse) {
    const formatter = new BulkKnowledgeFormatter();
    formattedText = formatter.format(data as BulkKnowledgeResponse);
    finalIsError = !data.success || data.errors.length > 0;
  } else {
    const formatter = new SingleKnowledgeFormatter();
    formattedText = formatter.format(data as SingleKnowledgeResponse);
    finalIsError = isError; // For single responses, rely on the passed isError or enhance if data has success field
  }
  return createToolResponse(formattedText, finalIsError);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_create/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { TaskResponse } from "../../../types/mcp.js";
import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator

/**
 * Defines a generic interface for formatting data into a string.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Extends the TaskResponse to include Neo4j properties structure
 */
interface SingleTaskResponse extends TaskResponse {
  properties?: any;
  identity?: number;
  labels?: string[];
  elementId?: string;
}

/**
 * Interface for bulk task creation response
 */
interface BulkTaskResponse {
  success: boolean;
  message: string;
  created: (TaskResponse & {
    properties?: any;
    identity?: number;
    labels?: string[];
    elementId?: string;
  })[];
  errors: {
    index: number;
    task: any; // Original input for the failed task
    error: {
      code: string;
      message: string;
      details?: any;
    };
  }[];
}

/**
 * Formatter for single task creation responses
 */
export class SingleTaskFormatter
  implements ResponseFormatter<SingleTaskResponse>
{
  format(data: SingleTaskResponse): string {
    // Extract task properties from Neo4j structure or direct data
    const taskData = data.properties || data;
    const {
      title,
      id,
      projectId,
      status,
      priority,
      taskType,
      createdAt,
      description,
      assignedTo,
      urls,
      tags,
      completionRequirements,
      dependencies,
      outputFormat,
      updatedAt,
    } = taskData;

    // Create a summary section
    const summary =
      `Task Created Successfully\n\n` +
      `Task: ${title || "Unnamed Task"}\n` +
      `ID: ${id || "Unknown ID"}\n` +
      `Project ID: ${projectId || "Unknown Project"}\n` +
      `Status: ${status || "Unknown Status"}\n` +
      `Priority: ${priority || "Unknown Priority"}\n` +
      `Type: ${taskType || "Unknown Type"}\n` +
      `Created: ${createdAt ? new Date(createdAt).toLocaleString() : "Unknown Date"}\n`;

    // Create a comprehensive details section
    let details = `Task Details:\n`;
    const fieldLabels: Record<keyof SingleTaskResponse, string> = {
      id: "ID",
      projectId: "Project ID",
      title: "Title",
      description: "Description",
      priority: "Priority",
      status: "Status",
      assignedTo: "Assigned To",
      urls: "URLs",
      tags: "Tags",
      completionRequirements: "Completion Requirements",
      dependencies: "Dependencies",
      outputFormat: "Output Format",
      taskType: "Task Type",
      createdAt: "Created At",
      updatedAt: "Updated At",
      properties: "Raw Properties",
      identity: "Neo4j Identity",
      labels: "Neo4j Labels",
      elementId: "Neo4j Element ID",
    };
    const relevantKeys: (keyof SingleTaskResponse)[] = [
      "id",
      "projectId",
      "title",
      "description",
      "priority",
      "status",
      "assignedTo",
      "urls",
      "tags",
      "completionRequirements",
      "dependencies",
      "outputFormat",
      "taskType",
      "createdAt",
      "updatedAt",
    ];

    relevantKeys.forEach((key) => {
      if (taskData[key] !== undefined && taskData[key] !== null) {
        let value = taskData[key];
        if (Array.isArray(value)) {
          value =
            value.length > 0
              ? value
                  .map((item) =>
                    typeof item === "object" ? JSON.stringify(item) : item,
                  )
                  .join(", ")
              : "None";
        } else if (
          typeof value === "string" &&
          (key === "createdAt" || key === "updatedAt")
        ) {
          try {
            value = new Date(value).toLocaleString();
          } catch (e) {
            /* Keep original */
          }
        }
        details += `  ${fieldLabels[key] || key}: ${value}\n`;
      }
    });

    return `${summary}\n${details}`;
  }
}

/**
 * Formatter for bulk task creation responses
 */
export class BulkTaskFormatter implements ResponseFormatter<BulkTaskResponse> {
  format(data: BulkTaskResponse): string {
    const { success, message, created, errors } = data;

    const summary =
      `${success && errors.length === 0 ? "Tasks Created Successfully" : "Task Creation Completed"}\n\n` +
      `Status: ${success && errors.length === 0 ? "✅ Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
      `Summary: ${message}\n` +
      `Created: ${created.length} task(s)\n` +
      `Errors: ${errors.length} error(s)\n`;

    let createdSection = "";
    if (created.length > 0) {
      createdSection = `\n--- Created Tasks (${created.length}) ---\n\n`;
      createdSection += created
        .map((task, index) => {
          const taskData = task.properties || task;
          return (
            `${index + 1}. ${taskData.title || "Unnamed Task"} (ID: ${taskData.id || "N/A"})\n` +
            `   Project ID: ${taskData.projectId || "N/A"}\n` +
            `   Priority: ${taskData.priority || "N/A"}\n` +
            `   Status: ${taskData.status || "N/A"}\n` +
            `   Created: ${taskData.createdAt ? new Date(taskData.createdAt).toLocaleString() : "N/A"}`
          );
        })
        .join("\n\n");
    }

    let errorsSection = "";
    if (errors.length > 0) {
      errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
      errorsSection += errors
        .map((errorItem, index) => {
          const taskTitle =
            errorItem.task?.title || `Input task at index ${errorItem.index}`;
          return (
            `${index + 1}. Error for task: "${taskTitle}" (Project ID: ${errorItem.task?.projectId || "N/A"})\n` +
            `   Error Code: ${errorItem.error.code}\n` +
            `   Message: ${errorItem.error.message}` +
            (errorItem.error.details
              ? `\n   Details: ${JSON.stringify(errorItem.error.details)}`
              : "")
          );
        })
        .join("\n\n");
    }

    return `${summary}${createdSection}${errorsSection}`.trim();
  }
}

/**
 * Create a formatted, human-readable response for the atlas_task_create tool
 *
 * @param data The raw task creation response data (SingleTaskResponse or BulkTaskResponse)
 * @param isError Whether this response represents an error condition (primarily for single responses)
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatTaskCreateResponse(data: any, isError = false): any {
  const isBulkResponse =
    data.hasOwnProperty("success") &&
    data.hasOwnProperty("created") &&
    data.hasOwnProperty("errors");

  let formattedText: string;
  let finalIsError: boolean;

  if (isBulkResponse) {
    const formatter = new BulkTaskFormatter();
    const bulkData = data as BulkTaskResponse;
    formattedText = formatter.format(bulkData);
    finalIsError = !bulkData.success || bulkData.errors.length > 0;
  } else {
    const formatter = new SingleTaskFormatter();
    // For single response, 'data' is the created task object.
    // 'isError' must be determined by the caller if an error occurred before this point.
    formattedText = formatter.format(data as SingleTaskResponse);
    finalIsError = isError;
  }
  return createToolResponse(formattedText, finalIsError);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_create/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { ProjectResponse } from "../../../types/mcp.js";
import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator

/**
 * Defines a generic interface for formatting data into a string.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Extends the ProjectResponse to include Neo4j properties structure
 */
interface SingleProjectResponse extends ProjectResponse {
  properties?: any;
  identity?: number;
  labels?: string[];
  elementId?: string;
}

/**
 * Interface for bulk project creation response
 */
interface BulkProjectResponse {
  success: boolean;
  message: string;
  created: (ProjectResponse & {
    properties?: any;
    identity?: number;
    labels?: string[];
    elementId?: string;
  })[];
  errors: {
    index: number;
    project: any; // Original input for the failed project
    error: {
      code: string;
      message: string;
      details?: any;
    };
  }[];
}

/**
 * Formatter for single project creation responses
 */
export class SingleProjectFormatter
  implements ResponseFormatter<SingleProjectResponse>
{
  format(data: SingleProjectResponse): string {
    // Extract project properties from Neo4j structure or direct data
    const projectData = data.properties || data;
    const {
      name,
      id,
      status,
      taskType,
      createdAt,
      description,
      urls,
      completionRequirements,
      outputFormat,
      updatedAt,
    } = projectData;

    // Create a summary section
    const summary =
      `Project Created Successfully\n\n` +
      `Project: ${name || "Unnamed Project"}\n` +
      `ID: ${id || "Unknown ID"}\n` +
      `Status: ${status || "Unknown Status"}\n` +
      `Type: ${taskType || "Unknown Type"}\n` +
      `Created: ${createdAt ? new Date(createdAt).toLocaleString() : "Unknown Date"}\n`;

    // Create a comprehensive details section
    const fieldLabels: Record<keyof SingleProjectResponse, string> = {
      id: "ID",
      name: "Name",
      description: "Description",
      status: "Status",
      urls: "URLs",
      completionRequirements: "Completion Requirements",
      outputFormat: "Output Format",
      taskType: "Task Type",
      createdAt: "Created At",
      updatedAt: "Updated At",
      // Neo4j specific fields
      properties: "Raw Properties",
      identity: "Neo4j Identity",
      labels: "Neo4j Labels",
      elementId: "Neo4j Element ID",
      // Fields from ProjectResponse that might not be in projectData directly if it's just properties
      dependencies: "Dependencies", // Assuming ProjectResponse might have this
    };

    let details = `Project Details:\n`;

    // Build details as key-value pairs for relevant fields
    const relevantKeys: (keyof SingleProjectResponse)[] = [
      "id",
      "name",
      "description",
      "status",
      "taskType",
      "completionRequirements",
      "outputFormat",
      "urls",
      "createdAt",
      "updatedAt",
    ];

    relevantKeys.forEach((key) => {
      if (projectData[key] !== undefined && projectData[key] !== null) {
        let value = projectData[key];

        if (Array.isArray(value)) {
          value =
            value.length > 0
              ? value
                  .map((item) =>
                    typeof item === "object" ? JSON.stringify(item) : item,
                  )
                  .join(", ")
              : "None";
        } else if (
          typeof value === "string" &&
          (key === "createdAt" || key === "updatedAt")
        ) {
          try {
            value = new Date(value).toLocaleString();
          } catch (e) {
            /* Keep original if parsing fails */
          }
        }

        details += `  ${fieldLabels[key] || key}: ${value}\n`;
      }
    });

    return `${summary}\n${details}`;
  }
}

/**
 * Formatter for bulk project creation responses
 */
export class BulkProjectFormatter
  implements ResponseFormatter<BulkProjectResponse>
{
  format(data: BulkProjectResponse): string {
    const { success, message, created, errors } = data;

    const summary =
      `${success && errors.length === 0 ? "Projects Created Successfully" : "Project Creation Completed"}\n\n` +
      `Status: ${success && errors.length === 0 ? "✅ Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
      `Summary: ${message}\n` +
      `Created: ${created.length} project(s)\n` +
      `Errors: ${errors.length} error(s)\n`;

    let createdSection = "";
    if (created.length > 0) {
      createdSection = `\n--- Created Projects (${created.length}) ---\n\n`;
      createdSection += created
        .map((project, index) => {
          const projectData = project.properties || project;
          return (
            `${index + 1}. ${projectData.name || "Unnamed Project"} (ID: ${projectData.id || "N/A"})\n` +
            `   Type: ${projectData.taskType || "N/A"}\n` +
            `   Status: ${projectData.status || "N/A"}\n` +
            `   Created: ${projectData.createdAt ? new Date(projectData.createdAt).toLocaleString() : "N/A"}`
          );
        })
        .join("\n\n");
    }

    let errorsSection = "";
    if (errors.length > 0) {
      errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
      errorsSection += errors
        .map((errorItem, index) => {
          const projectName =
            errorItem.project?.name ||
            `Input project at index ${errorItem.index}`;
          return (
            `${index + 1}. Error for project: "${projectName}"\n` +
            `   Error Code: ${errorItem.error.code}\n` +
            `   Message: ${errorItem.error.message}` +
            (errorItem.error.details
              ? `\n   Details: ${JSON.stringify(errorItem.error.details)}`
              : "")
          );
        })
        .join("\n\n");
    }

    return `${summary}${createdSection}${errorsSection}`.trim();
  }
}

/**
 * Create a formatted, human-readable response for the atlas_project_create tool
 *
 * @param data The raw project creation response data (SingleProjectResponse or BulkProjectResponse)
 * @param isError Whether this response represents an error condition (primarily for single responses)
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatProjectCreateResponse(data: any, isError = false): any {
  const isBulkResponse =
    data.hasOwnProperty("success") &&
    data.hasOwnProperty("created") &&
    data.hasOwnProperty("errors");

  let formattedText: string;
  let finalIsError: boolean;

  if (isBulkResponse) {
    const formatter = new BulkProjectFormatter();
    const bulkData = data as BulkProjectResponse;
    formattedText = formatter.format(bulkData);
    finalIsError = !bulkData.success || bulkData.errors.length > 0;
  } else {
    const formatter = new SingleProjectFormatter();
    // For single response, the 'data' is the project object itself.
    // 'isError' must be determined by the caller if an error occurred before this point.
    // If 'data' represents a successfully created project, isError should be false.
    formattedText = formatter.format(data as SingleProjectResponse);
    finalIsError = isError;
  }
  return createToolResponse(formattedText, finalIsError);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_create/types.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";
import {
  McpToolResponse,
  PriorityLevel,
  ResponseFormat,
  TaskStatus,
  TaskType,
  createPriorityLevelEnum,
  createResponseFormatEnum,
  createTaskStatusEnum,
  createTaskTypeEnum,
} from "../../../types/mcp.js";

export const TaskSchema = z.object({
  id: z.string().optional().describe("Optional client-generated task ID"),
  projectId: z
    .string()
    .describe("ID of the parent project this task belongs to"),
  title: z
    .string()
    .min(5)
    .max(150)
    .describe(
      "Concise task title clearly describing the objective (5-150 characters)",
    ),
  description: z
    .string()
    .describe("Detailed explanation of the task requirements and context"),
  priority: createPriorityLevelEnum()
    .default(PriorityLevel.MEDIUM)
    .describe("Importance level"),
  status: createTaskStatusEnum()
    .default(TaskStatus.TODO)
    .describe("Current task state"),
  assignedTo: z
    .string()
    .optional()
    .describe("ID of entity responsible for task completion"),
  urls: z
    .array(
      z.object({
        title: z.string(),
        url: z.string(),
      }),
    )
    .optional()
    .describe("Relevant URLs with descriptive titles for reference materials"),
  tags: z
    .array(z.string())
    .optional()
    .describe("Categorical labels for organization and filtering"),
  completionRequirements: z
    .string()
    .describe("Specific, measurable criteria that indicate task completion"),
  dependencies: z
    .array(z.string())
    .optional()
    .describe(
      "Array of existing task IDs that must be completed before this task can begin",
    ),
  outputFormat: z
    .string()
    .describe("Required format specification for task deliverables"),
  taskType: createTaskTypeEnum()
    .or(z.string())
    .describe("Classification of task purpose"),
});

const SingleTaskSchema = z
  .object({
    mode: z.literal("single"),
    id: z.string().optional(),
    projectId: z.string(),
    title: z.string().min(5).max(150),
    description: z.string(),
    priority: createPriorityLevelEnum()
      .optional()
      .default(PriorityLevel.MEDIUM),
    status: createTaskStatusEnum().optional().default(TaskStatus.TODO),
    assignedTo: z.string().optional(),
    urls: z
      .array(
        z.object({
          title: z.string(),
          url: z.string(),
        }),
      )
      .optional(),
    tags: z.array(z.string()).optional(),
    completionRequirements: z.string(),
    dependencies: z.array(z.string()).optional(),
    outputFormat: z.string(),
    taskType: createTaskTypeEnum().or(z.string()),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe("Creates a single task with comprehensive details and metadata");

const BulkTaskSchema = z
  .object({
    mode: z.literal("bulk"),
    tasks: z
      .array(TaskSchema)
      .min(1)
      .max(100)
      .describe(
        "Collection of task definitions to create in a single operation. Each object must include all fields required for single task creation (projectId, title, description, completionRequirements, outputFormat, taskType).",
      ),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe("Create multiple related tasks in a single efficient transaction");

// Schema shapes for tool registration
export const AtlasTaskCreateSchemaShape = {
  mode: z
    .enum(["single", "bulk"])
    .describe(
      "Operation mode - 'single' for creating one detailed task with full specifications, 'bulk' for efficiently creating multiple related tasks in a single transaction",
    ),
  id: z
    .string()
    .optional()
    .describe(
      "Optional client-generated task ID for consistent cross-referencing",
    ),
  projectId: z
    .string()
    .optional()
    .describe(
      "ID of the parent project this task belongs to, establishing the project-task relationship hierarchy (required for mode='single')",
    ),
  title: z
    .string()
    .min(5)
    .max(150)
    .optional()
    .describe(
      "Concise task title clearly describing the objective (5-150 characters) for display and identification (required for mode='single')",
    ),
  description: z
    .string()
    .optional()
    .describe(
      "Detailed explanation of the task requirements, context, approach, and implementation details (required for mode='single')",
    ),
  priority: createPriorityLevelEnum()
    .optional()
    .describe(
      "Importance level for task prioritization and resource allocation (Default: medium)",
    ),
  status: createTaskStatusEnum()
    .optional()
    .describe(
      "Current task workflow state for tracking task lifecycle and progress (Default: todo)",
    ),
  assignedTo: z
    .string()
    .optional()
    .describe(
      "ID of entity responsible for task completion and accountability tracking",
    ),
  urls: z
    .array(
      z.object({
        title: z.string(),
        url: z.string(),
      }),
    )
    .optional()
    .describe(
      "Array of relevant URLs with descriptive titles for reference materials",
    ),
  tags: z
    .array(z.string())
    .optional()
    .describe(
      "Array of categorical labels for task organization, filtering, and thematic grouping",
    ),
  completionRequirements: z
    .string()
    .optional()
    .describe(
      "Specific, measurable criteria that define when the task is considered complete and ready for verification (required for mode='single')",
    ),
  dependencies: z
    .array(z.string())
    .optional()
    .describe(
      "Array of existing task IDs that must be completed before this task can begin, creating sequential workflow paths and prerequisites",
    ),
  outputFormat: z
    .string()
    .optional()
    .describe(
      "Required format and structure specification for the task's deliverables, artifacts, and documentation (required for mode='single')",
    ),
  taskType: createTaskTypeEnum()
    .or(z.string())
    .optional()
    .describe(
      "Classification of task purpose for workflow organization, filtering, and reporting (required for mode='single')",
    ),
  tasks: z
    .array(TaskSchema)
    .min(1)
    .max(100)
    .optional()
    .describe(
      "Array of complete task definition objects to create in a single transaction (supports 1-100 tasks, required for mode='bulk'). Each object must include all fields required for single task creation (projectId, title, description, completionRequirements, outputFormat, taskType).",
    ),
  responseFormat: createResponseFormatEnum()
    .optional()
    .describe(
      "Desired response format: 'formatted' (default string) or 'json' (raw object)",
    ),
} as const;

// Schema for validation
export const AtlasTaskCreateSchema = z.discriminatedUnion("mode", [
  SingleTaskSchema,
  BulkTaskSchema,
]);

export type AtlasTaskCreateInput = z.infer<typeof AtlasTaskCreateSchema>;
export type TaskInput = z.infer<typeof TaskSchema>;
export type AtlasTaskCreateResponse = McpToolResponse;

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_list/responseFormat.ts:
--------------------------------------------------------------------------------

```typescript
import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator
import { Project, ProjectListResponse } from "./types.js";

/**
 * Defines a generic interface for formatting data into a string.
 */
interface ResponseFormatter<T> {
  format(data: T): string;
}

/**
 * Formatter for structured project query responses
 */
export class ProjectListFormatter
  implements ResponseFormatter<ProjectListResponse>
{
  /**
   * Get an emoji indicator for the task status
   */
  private getStatusEmoji(status: string): string {
    switch (status) {
      case "backlog":
        return "📋";
      case "todo":
        return "📝";
      case "in_progress":
        return "🔄";
      case "completed":
        return "✅";
      default:
        return "❓";
    }
  }

  /**
   * Get a visual indicator for the priority level
   */
  private getPriorityIndicator(priority: string): string {
    switch (priority) {
      case "critical":
        return "[!!!]";
      case "high":
        return "[!!]";
      case "medium":
        return "[!]";
      case "low":
        return "[-]";
      default:
        return "[?]";
    }
  }
  format(data: ProjectListResponse): string {
    const { projects, total, page, limit, totalPages } = data;

    // Generate result summary section
    const summary =
      `Project Portfolio\n\n` +
      `Total Entities: ${total}\n` +
      `Page: ${page} of ${totalPages}\n` +
      `Displaying: ${Math.min(limit, projects.length)} project(s) per page\n`;

    if (projects.length === 0) {
      return `${summary}\n\nNo project entities matched the specified criteria`;
    }

    // Format each project
    const projectsSections = projects
      .map((project, index) => {
        // Access properties directly from the project object
        const { name, id, status, taskType, createdAt } = project;

        let projectSection =
          `${index + 1}. ${name || "Unnamed Project"}\n\n` +
          `ID: ${id || "Unknown ID"}\n` +
          `Status: ${status || "Unknown Status"}\n` +
          `Type: ${taskType || "Unknown Type"}\n` +
          `Created: ${createdAt ? new Date(createdAt).toLocaleString() : "Unknown Date"}\n`;

        // Add project details in plain text format
        projectSection += `\nProject Details\n\n`;

        // Add each property with proper formatting, accessing directly from 'project'
        if (project.id) projectSection += `ID: ${project.id}\n`;
        if (project.name) projectSection += `Name: ${project.name}\n`;
        if (project.description)
          projectSection += `Description: ${project.description}\n`;
        if (project.status) projectSection += `Status: ${project.status}\n`;

        // Format URLs array
        if (project.urls) {
          const urlsValue =
            Array.isArray(project.urls) && project.urls.length > 0
              ? project.urls
                  .map((u) => `${u.title}: ${u.url}`)
                  .join("\n           ") // Improved formatting for URLs
              : "None";
          projectSection += `URLs: ${urlsValue}\n`;
        }

        if (project.completionRequirements)
          projectSection += `Completion Requirements: ${project.completionRequirements}\n`;
        if (project.outputFormat)
          projectSection += `Output Format: ${project.outputFormat}\n`;
        if (project.taskType)
          projectSection += `Task Type: ${project.taskType}\n`;

        // Format dates
        if (project.createdAt) {
          const createdDate =
            typeof project.createdAt === "string" &&
            /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(project.createdAt)
              ? new Date(project.createdAt).toLocaleString()
              : project.createdAt;
          projectSection += `Created At: ${createdDate}\n`;
        }

        if (project.updatedAt) {
          const updatedDate =
            typeof project.updatedAt === "string" &&
            /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(project.updatedAt)
              ? new Date(project.updatedAt).toLocaleString()
              : project.updatedAt;
          projectSection += `Updated At: ${updatedDate}\n`;
        }

        // Add tasks if included
        if (project.tasks && project.tasks.length > 0) {
          projectSection += `\nTasks (${project.tasks.length}):\n`;

          projectSection += project.tasks
            .map((task, taskIndex) => {
              const taskTitle = task.title || "Unnamed Task";
              const taskId = task.id || "Unknown ID";
              const taskStatus = task.status || "Unknown Status";
              const taskPriority = task.priority || "Unknown Priority";
              const taskCreatedAt = task.createdAt
                ? new Date(task.createdAt).toLocaleString()
                : "Unknown Date";

              const statusEmoji = this.getStatusEmoji(taskStatus);
              const priorityIndicator = this.getPriorityIndicator(taskPriority);

              return (
                `  ${taskIndex + 1}. ${statusEmoji} ${priorityIndicator} ${taskTitle}\n` +
                `     ID: ${taskId}\n` +
                `     Status: ${taskStatus}\n` +
                `     Priority: ${taskPriority}\n` +
                `     Created: ${taskCreatedAt}`
              );
            })
            .join("\n\n");
          projectSection += "\n";
        }

        // Add knowledge if included
        if (project.knowledge && project.knowledge.length > 0) {
          projectSection += `\nKnowledge Items (${project.knowledge.length}):\n`;

          projectSection += project.knowledge
            .map((item, itemIndex) => {
              return (
                `  ${itemIndex + 1}. ${item.domain || "Uncategorized"} (ID: ${item.id || "N/A"})\n` +
                `     Tags: ${item.tags && item.tags.length > 0 ? item.tags.join(", ") : "None"}\n` +
                `     Created: ${item.createdAt ? new Date(item.createdAt).toLocaleString() : "N/A"}\n` +
                `     Content Preview: ${item.text || "No content available"}`
              ); // Preview already truncated if needed
            })
            .join("\n\n");
          projectSection += "\n";
        }

        return projectSection;
      })
      .join("\n\n----------\n\n");

    // Append pagination metadata for multi-page results
    let paginationInfo = "";
    if (totalPages > 1) {
      paginationInfo =
        `\n\nPagination Controls:\n` + // Added colon for clarity
        `Viewing page ${page} of ${totalPages}.\n` +
        `${page < totalPages ? "Use 'page' parameter to navigate to additional results." : "You are on the last page."}`;
    }

    return `${summary}\n\n${projectsSections}${paginationInfo}`;
  }
}

/**
 * Create a human-readable formatted response for the atlas_project_list tool
 *
 * @param data The structured project query response data
 * @param isError Whether this response represents an error condition
 * @returns Formatted MCP tool response with appropriate structure
 */
export function formatProjectListResponse(data: any, isError = false): any {
  const formatter = new ProjectListFormatter();
  const formattedText = formatter.format(data as ProjectListResponse); // Assuming data is ProjectListResponse
  return createToolResponse(formattedText, isError);
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_list/listProjects.ts:
--------------------------------------------------------------------------------

```typescript
import {
  KnowledgeService,
  ProjectService,
  TaskService,
} from "../../../services/neo4j/index.js";
import { BaseErrorCode, McpError } from "../../../types/errors.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import {
  Project,
  ProjectListRequest,
  ProjectListResponse,
  Knowledge,
  Task,
} from "./types.js"; // Import Knowledge and Task

/**
 * Retrieve and filter project entities based on specified criteria
 * Provides two query modes: detailed entity retrieval or paginated collection listing
 *
 * @param request The project query parameters including filters and pagination controls
 * @returns Promise resolving to structured project entities with optional related resources
 */
export async function listProjects(
  request: ProjectListRequest,
): Promise<ProjectListResponse> {
  const reqContext = requestContextService.createRequestContext({
    toolName: "listProjects",
    requestMode: request.mode,
  });
  try {
    const {
      mode = "all",
      id,
      page = 1,
      limit = 20,
      includeKnowledge = false,
      includeTasks = false,
      taskType,
      status,
    } = request;

    // Parameter validation
    if (mode === "details" && !id) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        'Project identifier is required when using mode="details"',
      );
    }

    // Sanitize pagination parameters
    const validatedPage = Math.max(1, page);
    const validatedLimit = Math.min(Math.max(1, limit), 100);

    let projects: Project[] = [];
    let total = 0;
    let totalPages = 0;

    if (mode === "details") {
      // Retrieve specific project entity by identifier
      const projectResult = await ProjectService.getProjectById(id!);

      if (!projectResult) {
        throw new McpError(
          BaseErrorCode.NOT_FOUND,
          `Project with identifier ${id} not found`,
        );
      }

      // Cast to the tool's Project type
      projects = [projectResult as Project];
      total = 1;
      totalPages = 1;
    } else {
      // Get paginated list of projects with filters
      const projectsResult = await ProjectService.getProjects({
        status,
        taskType,
        page: validatedPage,
        limit: validatedLimit,
      });

      // Cast each project to the tool's Project type
      projects = projectsResult.data.map((p) => p as Project);
      total = projectsResult.total;
      totalPages = projectsResult.totalPages;
    }

    // Process knowledge resource associations if requested
    if (includeKnowledge && projects.length > 0) {
      for (const project of projects) {
        if (mode === "details") {
          // For detailed view, retrieve comprehensive knowledge resources
          const knowledgeResult = await KnowledgeService.getKnowledge({
            projectId: project.id, // Access directly
            page: 1,
            limit: 100, // Reasonable threshold for associated resources
          });

          // Add debug logging
          logger.info("Knowledge items retrieved", {
            ...reqContext,
            projectId: project.id, // Access directly
            count: knowledgeResult.data.length,
            firstItem: knowledgeResult.data[0]
              ? JSON.stringify(knowledgeResult.data[0])
              : "none",
          });

          // Map directly, assuming KnowledgeService returns Neo4jKnowledge objects
          project.knowledge = knowledgeResult.data.map((item) => {
            // More explicit mapping with debug info
            logger.debug("Processing knowledge item", {
              ...reqContext,
              id: item.id,
              domain: item.domain,
              textLength: item.text ? item.text.length : 0,
            });

            // Cast to the tool's Knowledge type
            return item as Knowledge;
          });
        } else {
          // For list mode, get abbreviated knowledge items
          const knowledgeResult = await KnowledgeService.getKnowledge({
            projectId: project.id, // Access directly
            page: 1,
            limit: 5, // Just a few for summary view
          });

          // Map directly, assuming KnowledgeService returns Neo4jKnowledge objects
          project.knowledge = knowledgeResult.data.map((item) => {
            // Cast to the tool's Knowledge type, potentially truncating text
            const knowledgeItem = item as Knowledge;
            return {
              ...knowledgeItem,
              // Show a preview of the text - increased to 200 characters
              text:
                item.text && item.text.length > 200
                  ? item.text.substring(0, 200) + "... (truncated)"
                  : item.text,
            };
          });
        }
      }
    }

    // Process task entity associations if requested
    if (includeTasks && projects.length > 0) {
      for (const project of projects) {
        if (mode === "details") {
          // For detailed view, retrieve prioritized task entities
          const tasksResult = await TaskService.getTasks({
            projectId: project.id, // Access directly
            page: 1,
            limit: 100, // Reasonable threshold for associated entities
            sortBy: "priority",
            sortDirection: "desc",
          });

          // Add debug logging
          logger.info("Tasks retrieved for project", {
            ...reqContext,
            projectId: project.id, // Access directly
            count: tasksResult.data.length,
            firstItem: tasksResult.data[0]
              ? JSON.stringify(tasksResult.data[0])
              : "none",
          });

          // Map directly, assuming TaskService returns Neo4jTask objects
          project.tasks = tasksResult.data.map((item) => {
            // Debug info
            logger.debug("Processing task item", {
              ...reqContext,
              id: item.id,
              title: item.title,
              status: item.status,
              priority: item.priority,
            });

            // Cast to the tool's Task type
            return item as Task;
          });
        } else {
          // For list mode, get abbreviated task items
          const tasksResult = await TaskService.getTasks({
            projectId: project.id, // Access directly
            page: 1,
            limit: 5, // Just a few for summary view
            sortBy: "priority",
            sortDirection: "desc",
          });

          // Map directly, assuming TaskService returns Neo4jTask objects
          project.tasks = tasksResult.data.map((item) => {
            // Cast to the tool's Task type
            return item as Task;
          });
        }
      }
    }

    // Construct the response
    const response: ProjectListResponse = {
      projects,
      total,
      page: validatedPage,
      limit: validatedLimit,
      totalPages,
    };

    logger.info("Project query executed successfully", {
      ...reqContext,
      mode,
      count: projects.length,
      total,
      includeKnowledge,
      includeTasks,
    });

    return response;
  } catch (error) {
    logger.error("Project query execution failed", error as Error, reqContext);

    if (error instanceof McpError) {
      throw error;
    }

    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Failed to retrieve project entities: ${error instanceof Error ? error.message : String(error)}`,
    );
  }
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_add/index.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasAddKnowledge } from "./addKnowledge.js";
import { AtlasKnowledgeAddSchemaShape } from "./types.js";

export const registerAtlasKnowledgeAddTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_knowledge_add",
    "Adds a new knowledge item or multiple items to the system with domain categorization, tagging, and citation support",
    AtlasKnowledgeAddSchemaShape,
    atlasAddKnowledge,
    createToolMetadata({
      examples: [
        createToolExample(
          {
            mode: "single",
            projectId: "proj_ms_migration",
            text: "GraphQL provides significant performance benefits over REST when clients need to request multiple related resources. By allowing clients to specify exactly what data they need in a single request, GraphQL eliminates over-fetching and under-fetching problems common in REST APIs.",
            domain: "technical",
            tags: ["graphql", "api", "performance", "rest"],
            citations: [
              "https://graphql.org/learn/best-practices/",
              "https://www.apollographql.com/blog/graphql/basics/graphql-vs-rest/",
            ],
          },
          `{
            "id": "know_graphql_benefits",
            "projectId": "proj_ms_migration",
            "text": "GraphQL provides significant performance benefits over REST when clients need to request multiple related resources. By allowing clients to specify exactly what data they need in a single request, GraphQL eliminates over-fetching and under-fetching problems common in REST APIs.",
            "tags": ["graphql", "api", "performance", "rest"],
            "domain": "technical",
            "citations": ["https://graphql.org/learn/best-practices/", "https://www.apollographql.com/blog/graphql/basics/graphql-vs-rest/"],
            "createdAt": "2025-03-23T10:11:24.123Z",
            "updatedAt": "2025-03-23T10:11:24.123Z"
          }`,
          "Add technical knowledge about GraphQL benefits with citations and tags",
        ),
        createToolExample(
          {
            mode: "bulk",
            knowledge: [
              {
                projectId: "proj_ui_redesign",
                text: "User interviews revealed that 78% of our customers struggle with the current checkout flow, particularly the address entry form which was described as 'confusing' and 'overly complex'.",
                domain: "business",
                tags: ["user-research", "checkout", "ux-issues"],
              },
              {
                projectId: "proj_ui_redesign",
                text: "Industry research shows that automatically formatting phone numbers and credit card fields as users type reduces error rates by approximately 25%. Implementing real-time validation with clear error messages has been shown to decrease form abandonment rates by up to 40%.",
                domain: "technical",
                tags: ["form-design", "validation", "ux-patterns"],
                citations: [
                  "https://baymard.com/blog/input-mask-form-fields",
                  "https://www.smashingmagazine.com/2020/03/form-validation-ux-design/",
                ],
              },
            ],
          },
          `{
            "success": true,
            "message": "Successfully added 2 knowledge items",
            "created": [
              {
                "id": "know_checkout_research",
                "projectId": "proj_ui_redesign",
                "text": "User interviews revealed that 78% of our customers struggle with the current checkout flow, particularly the address entry form which was described as 'confusing' and 'overly complex'.",
                "tags": ["user-research", "checkout", "ux-issues"],
                "domain": "business",
                "citations": [],
                "createdAt": "2025-03-23T10:11:24.123Z",
                "updatedAt": "2025-03-23T10:11:24.123Z"
              },
              {
                "id": "know_form_validation",
                "projectId": "proj_ui_redesign",
                "text": "Industry research shows that automatically formatting phone numbers and credit card fields as users type reduces error rates by approximately 25%. Implementing real-time validation with clear error messages has been shown to decrease form abandonment rates by up to 40%.",
                "tags": ["form-design", "validation", "ux-patterns"],
                "domain": "technical",
                "citations": ["https://baymard.com/blog/input-mask-form-fields", "https://www.smashingmagazine.com/2020/03/form-validation-ux-design/"],
                "createdAt": "2025-03-23T10:11:24.456Z",
                "updatedAt": "2025-03-23T10:11:24.456Z"
              }
            ],
            "errors": []
          }`,
          "Add multiple knowledge items with mixed domains and research findings",
        ),
      ],
      requiredPermission: "knowledge:create",
      returnSchema: z.union([
        // Single knowledge response
        z.object({
          id: z.string().describe("Knowledge ID"),
          projectId: z.string().describe("Project ID"),
          text: z.string().describe("Knowledge content"),
          tags: z.array(z.string()).describe("Categorical labels"),
          domain: z.string().describe("Knowledge domain"),
          citations: z.array(z.string()).describe("Reference sources"),
          createdAt: z.string().describe("Creation timestamp"),
          updatedAt: z.string().describe("Last update timestamp"),
        }),
        // Bulk creation response
        z.object({
          success: z.boolean().describe("Operation success status"),
          message: z.string().describe("Result message"),
          created: z
            .array(
              z.object({
                id: z.string().describe("Knowledge ID"),
                projectId: z.string().describe("Project ID"),
                text: z.string().describe("Knowledge content"),
                tags: z.array(z.string()).describe("Categorical labels"),
                domain: z.string().describe("Knowledge domain"),
                citations: z.array(z.string()).describe("Reference sources"),
                createdAt: z.string().describe("Creation timestamp"),
                updatedAt: z.string().describe("Last update timestamp"),
              }),
            )
            .describe("Created knowledge items"),
          errors: z
            .array(
              z.object({
                index: z.number().describe("Index in the knowledge array"),
                knowledge: z.any().describe("Original knowledge data"),
                error: z
                  .object({
                    code: z.string().describe("Error code"),
                    message: z.string().describe("Error message"),
                    details: z
                      .any()
                      .optional()
                      .describe("Additional error details"),
                  })
                  .describe("Error information"),
              }),
            )
            .describe("Creation errors"),
        }),
      ]),
      rateLimit: {
        windowMs: 60 * 1000, // 1 minute
        maxRequests: 20, // 20 requests per minute (higher than project creation as knowledge items are typically smaller)
      },
    }),
  );
};

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_list/index.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import {
  ResponseFormat,
  createResponseFormatEnum,
  createToolResponse,
} from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { listKnowledge } from "./listKnowledge.js";
import { formatKnowledgeListResponse } from "./responseFormat.js";
import { KnowledgeListRequest } from "./types.js"; // Corrected import name

/**
 * Registers the atlas_knowledge_list tool with the MCP server
 *
 * @param server The MCP server instance
 */
export function registerAtlasKnowledgeListTool(server: McpServer): void {
  registerTool(
    server,
    "atlas_knowledge_list",
    "Lists knowledge items according to specified filters with tag-based categorization, domain filtering, and full-text search capabilities",
    {
      projectId: z
        .string()
        .describe("ID of the project to list knowledge items for (required)"),
      tags: z
        .array(z.string())
        .optional()
        .describe(
          "Array of tags to filter by (items matching any tag will be included)",
        ),
      domain: z
        .string()
        .optional()
        .describe("Filter by knowledge domain/category"),
      search: z
        .string()
        .optional()
        .describe("Text search query to filter results by content relevance"),
      page: z
        .number()
        .min(1)
        .optional()
        .default(1)
        .describe("Page number for paginated results (Default: 1)"),
      limit: z
        .number()
        .min(1)
        .max(100)
        .optional()
        .default(20)
        .describe("Number of results per page, maximum 100 (Default: 20)"),
      responseFormat: createResponseFormatEnum()
        .optional()
        .default(ResponseFormat.FORMATTED)
        .describe(
          "Desired response format: 'formatted' (default string) or 'json' (raw object)",
        ),
    },
    async (input, context) => {
      // Process knowledge list request
      const validatedInput = input as unknown as KnowledgeListRequest & {
        responseFormat?: ResponseFormat;
      }; // Corrected type cast
      const result = await listKnowledge(validatedInput);

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(result, null, 2));
      } else {
        // Return the result using the formatter for rich display
        return formatKnowledgeListResponse(result, false);
      }
    },
    createToolMetadata({
      examples: [
        createToolExample(
          {
            projectId: "proj_ms_migration",
            limit: 5,
          },
          `{
            "knowledge": [
              {
                "id": "know_saga_pattern",
                "projectId": "proj_ms_migration",
                "projectName": "Microservice Architecture Migration",
                "text": "Distributed transactions must use Saga pattern with compensating actions to maintain data integrity across services",
                "tags": ["architecture", "data-integrity", "patterns"],
                "domain": "technical",
                "citations": ["https://microservices.io/patterns/data/saga.html"],
                "createdAt": "2025-03-23T11:22:14.789Z",
                "updatedAt": "2025-03-23T11:22:14.789Z"
              },
              {
                "id": "know_rate_limiting",
                "projectId": "proj_ms_migration",
                "projectName": "Microservice Architecture Migration",
                "text": "Rate limiting should be implemented at the API Gateway level using Redis-based token bucket algorithm",
                "tags": ["api-gateway", "performance", "security"],
                "domain": "technical",
                "citations": ["https://www.nginx.com/blog/rate-limiting-nginx/"],
                "createdAt": "2025-03-23T12:34:27.456Z",
                "updatedAt": "2025-03-23T12:34:27.456Z"
              }
            ],
            "total": 2,
            "page": 1,
            "limit": 5,
            "totalPages": 1
          }`,
          "Retrieve all knowledge items for a specific project",
        ),
        createToolExample(
          {
            projectId: "proj_ms_migration",
            domain: "technical",
            tags: ["security"],
          },
          `{
            "knowledge": [
              {
                "id": "know_rate_limiting",
                "projectId": "proj_ms_migration",
                "projectName": "Microservice Architecture Migration",
                "text": "Rate limiting should be implemented at the API Gateway level using Redis-based token bucket algorithm",
                "tags": ["api-gateway", "performance", "security"],
                "domain": "technical",
                "citations": ["https://www.nginx.com/blog/rate-limiting-nginx/"],
                "createdAt": "2025-03-23T12:34:27.456Z",
                "updatedAt": "2025-03-23T12:34:27.456Z"
              }
            ],
            "total": 1,
            "page": 1,
            "limit": 20,
            "totalPages": 1
          }`,
          "Filter knowledge items by domain and tags",
        ),
        createToolExample(
          {
            projectId: "proj_ms_migration",
            search: "data integrity",
          },
          `{
            "knowledge": [
              {
                "id": "know_saga_pattern",
                "projectId": "proj_ms_migration",
                "projectName": "Microservice Architecture Migration",
                "text": "Distributed transactions must use Saga pattern with compensating actions to maintain data integrity across services",
                "tags": ["architecture", "data-integrity", "patterns"],
                "domain": "technical",
                "citations": ["https://microservices.io/patterns/data/saga.html"],
                "createdAt": "2025-03-23T11:22:14.789Z",
                "updatedAt": "2025-03-23T11:22:14.789Z"
              }
            ],
            "total": 1,
            "page": 1,
            "limit": 20,
            "totalPages": 1
          }`,
          "Search knowledge items for specific text content",
        ),
      ],
      requiredPermission: "knowledge:read",
      entityType: "knowledge",
      returnSchema: z.object({
        knowledge: z.array(
          z.object({
            id: z.string().describe("Knowledge ID"),
            projectId: z.string().describe("Project ID"),
            projectName: z.string().optional().describe("Project name"),
            text: z.string().describe("Knowledge content"),
            tags: z.array(z.string()).optional().describe("Categorical labels"),
            domain: z.string().describe("Knowledge domain/category"),
            citations: z
              .array(z.string())
              .optional()
              .describe("Reference sources"),
            createdAt: z.string().describe("Creation timestamp"),
            updatedAt: z.string().describe("Last update timestamp"),
          }),
        ),
        total: z
          .number()
          .describe("Total number of knowledge items matching criteria"),
        page: z.number().describe("Current page number"),
        limit: z.number().describe("Number of items per page"),
        totalPages: z.number().describe("Total number of pages"),
      }),
      rateLimit: {
        windowMs: 60 * 1000, // 1 minute
        maxRequests: 30, // 30 requests per minute
      },
    }),
  );
}

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_unified_search/unifiedSearch.ts:
--------------------------------------------------------------------------------

```typescript
import {
  SearchResultItem,
  SearchService,
} from "../../../services/neo4j/index.js";
import { PaginatedResult } from "../../../services/neo4j/types.js";
import { BaseErrorCode, McpError } from "../../../types/errors.js";
import { ResponseFormat } from "../../../types/mcp.js";
import { ToolContext } from "../../../types/tool.js";
import { logger, requestContextService } from "../../../utils/index.js";
import { formatUnifiedSearchResponse } from "./responseFormat.js";
import {
  UnifiedSearchRequestInput,
  UnifiedSearchRequestSchema,
  UnifiedSearchResponse,
} from "./types.js";

export const atlasUnifiedSearch = async (
  input: unknown,
  context: ToolContext,
): Promise<any> => {
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasUnifiedSearch",
    });
  try {
    const validatedInput = UnifiedSearchRequestSchema.parse(
      input,
    ) as UnifiedSearchRequestInput & { responseFormat?: ResponseFormat };

    logger.info("Performing unified search", {
      ...reqContext,
      input: validatedInput,
    });

    if (!validatedInput.value || validatedInput.value.trim() === "") {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        "Search value cannot be empty",
        { param: "value" },
      );
    }

    let searchResults: PaginatedResult<SearchResultItem>;
    const propertyForSearch = validatedInput.property?.trim();
    const entityTypesForSearch = validatedInput.entityTypes || [
      "project",
      "task",
      "knowledge",
    ]; // Default if not provided

    // Determine if we should use full-text for the given property and entity type
    let shouldUseFullText = false;
    if (propertyForSearch) {
      const lowerProp = propertyForSearch.toLowerCase();
      // Check for specific entityType + property combinations that have dedicated full-text indexes
      if (entityTypesForSearch.includes("knowledge") && lowerProp === "text") {
        shouldUseFullText = true;
      } else if (
        entityTypesForSearch.includes("project") &&
        (lowerProp === "name" || lowerProp === "description")
      ) {
        shouldUseFullText = true;
      } else if (
        entityTypesForSearch.includes("task") &&
        (lowerProp === "title" || lowerProp === "description")
      ) {
        shouldUseFullText = true;
      }
      // Add other specific full-text indexed fields here if any
    } else {
      // No specific property, so general full-text search is appropriate across default indexed fields
      shouldUseFullText = true;
    }

    if (shouldUseFullText) {
      logger.info(
        `Using full-text search. Property: '${propertyForSearch || "default fields"}'`,
        {
          ...reqContext,
          property: propertyForSearch,
          targetEntityTypes: entityTypesForSearch,
          effectiveFuzzy: validatedInput.fuzzy === true,
        },
      );

      const escapeLucene = (str: string) =>
        str.replace(/([+\-!(){}\[\]^"~*?:\\\/"])/g, "\\$1");
      let luceneQueryValue = escapeLucene(validatedInput.value);

      // If fuzzy is requested for the tool, apply it to the Lucene query
      if (validatedInput.fuzzy === true) {
        luceneQueryValue = `${luceneQueryValue}~1`;
      }
      // Note: If propertyForSearch is set (e.g., "text" for "knowledge"),
      // SearchService.fullTextSearch will use the appropriate index (e.g., "knowledge_fulltext").
      // Lucene itself can handle field-specific queries like "fieldName:term",
      // but our SearchService.fullTextSearch is already structured to call specific indexes.
      // So, just passing the term (and fuzzy if needed) is correct here.

      logger.debug("Constructed Lucene query value for full-text search", {
        ...reqContext,
        luceneQueryValue,
      });

      searchResults = await SearchService.fullTextSearch(luceneQueryValue, {
        entityTypes: entityTypesForSearch,
        taskType: validatedInput.taskType,
        page: validatedInput.page,
        limit: validatedInput.limit,
      });
    } else {
      // propertyForSearch is specified, and it's not one we've decided to use full-text for
      // This path implies a regex-based search on a specific, non-full-text-optimized property.
      // We want "contains" (fuzzy: true for SearchService.search) by default for this path,
      // unless the user explicitly passed fuzzy: false in the tool input.
      let finalFuzzyForRegexPath: boolean;
      if ((input as any)?.fuzzy === false) {
        // User explicitly requested an exact match for the regex search
        finalFuzzyForRegexPath = false;
      } else {
        // User either passed fuzzy: true, or didn't pass fuzzy (in which case Zod default is true,
        // and we also want "contains" as the intelligent default for this path).
        finalFuzzyForRegexPath = true;
      }

      logger.info(
        `Using regex-based search for specific property: '${propertyForSearch}'. Effective fuzzy for SearchService.search (true means contains): ${finalFuzzyForRegexPath}`,
        {
          ...reqContext,
          property: propertyForSearch,
          targetEntityTypes: entityTypesForSearch,
          userInputFuzzy: (input as any)?.fuzzy, // Log what user actually passed, if anything
          zodParsedFuzzy: validatedInput.fuzzy, // Log what Zod parsed (with default)
          finalFuzzyForRegexPath,
        },
      );

      searchResults = await SearchService.search({
        property: propertyForSearch, // Already trimmed
        value: validatedInput.value,
        entityTypes: entityTypesForSearch,
        caseInsensitive: validatedInput.caseInsensitive, // Pass through
        fuzzy: finalFuzzyForRegexPath, // This now correctly defaults to 'true' for "contains"
        taskType: validatedInput.taskType,
        assignedToUserId: validatedInput.assignedToUserId, // Pass through
        page: validatedInput.page,
        limit: validatedInput.limit,
      });
    }

    if (!searchResults || !Array.isArray(searchResults.data)) {
      logger.error(
        "Search service returned invalid data structure.",
        new Error("Invalid search results structure"),
        { ...reqContext, searchResultsReceived: searchResults },
      );
      throw new McpError(
        BaseErrorCode.INTERNAL_ERROR,
        "Received invalid data structure from search service.",
      );
    }

    logger.info("Unified search completed successfully", {
      ...reqContext,
      resultCount: searchResults.data.length,
      totalResults: searchResults.total,
    });

    const responseData: UnifiedSearchResponse = {
      results: searchResults.data,
      total: searchResults.total,
      page: searchResults.page,
      limit: searchResults.limit,
      totalPages: searchResults.totalPages,
    };

    if (validatedInput.responseFormat === ResponseFormat.JSON) {
      return responseData;
    } else {
      return formatUnifiedSearchResponse(responseData);
    }
  } catch (error) {
    const errorMessage =
      error instanceof Error ? error.message : "Unknown error";
    // const errorStack = error instanceof Error ? error.stack : undefined; // Already captured by logger
    logger.error("Failed to perform unified search", error as Error, {
      ...reqContext,
      // errorMessage and errorStack are part of the Error object passed to logger
      inputReceived: input,
    });

    if (error instanceof McpError) {
      throw error;
    } else {
      throw new McpError(
        BaseErrorCode.INTERNAL_ERROR,
        `Error performing unified search: ${errorMessage}`,
      );
    }
  }
};

```

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

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

// Imports MUST be at the top level
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import http from "http";
import { config, environment } from "./config/index.js"; // This loads .env via dotenv.config()
import { initializeAndStartServer } from "./mcp/server.js";
import { closeNeo4jConnection } from "./services/neo4j/index.js";
import { logger, McpLogLevel, requestContextService } from "./utils/index.js";

/**
 * The main MCP server instance, stored if transport is stdio for shutdown.
 * Or the HTTP server instance if transport is http.
 * @type {McpServer | http.Server | undefined}
 */
let serverInstance: McpServer | http.Server | undefined;

/**
 * Gracefully shuts down the main MCP server and related services.
 * Handles process termination signals (SIGTERM, SIGINT) and critical errors.
 *
 * @param signal - The signal or event name that triggered the shutdown (e.g., "SIGTERM", "uncaughtException").
 */
const shutdown = async (signal: string) => {
  // Create a proper RequestContext for shutdown operations
  const shutdownContext = requestContextService.createRequestContext({
    operation: "Shutdown",
    signal,
    appName: config.mcpServerName,
  });

  logger.info(
    `Received ${signal}. Starting graceful shutdown for ${config.mcpServerName}...`,
    shutdownContext,
  );

  try {
    if (serverInstance) {
      if (serverInstance instanceof McpServer) {
        logger.info("Closing main MCP server (stdio) instance...", shutdownContext);
        await serverInstance.close();
        logger.info(
          "Main MCP server (stdio) instance closed successfully.",
          shutdownContext,
        );
      } else if (serverInstance instanceof http.Server) {
        logger.info("Closing HTTP server instance...", shutdownContext);
        const currentHttpServer = serverInstance;
        await new Promise<void>((resolve, reject) => {
          currentHttpServer.close((err?: Error) => {
            if (err) {
              logger.error("Error closing HTTP server", err, shutdownContext);
              return reject(err);
            }
            logger.info("HTTP server instance closed successfully.", shutdownContext);
            resolve();
          });
        });
      }
    } else {
      logger.info(
        "No global MCP server instance to close (expected for HTTP transport or if not yet initialized).",
        shutdownContext,
      );
    }

    logger.info("Closing Neo4j driver connection...", shutdownContext);
    await closeNeo4jConnection();
    logger.info(
      "Neo4j driver connection closed successfully.",
      shutdownContext,
    );

    logger.info(
      `Graceful shutdown for ${config.mcpServerName} completed successfully. Exiting.`,
      shutdownContext,
    );
    process.exit(0);
  } catch (error) {
    // Pass the error object directly as the second argument to logger.error
    logger.error("Critical error during shutdown", error as Error, {
      ...shutdownContext,
      // error message and stack are now part of the Error object passed to logger
    });
    process.exit(1);
  }
};

/**
 * Initializes and starts the main MCP server.
 * Sets up logging, request context, initializes the server instance, starts the transport,
 * and registers signal handlers for graceful shutdown and error handling.
 */
const start = async () => {
  // --- Logger Initialization ---
  const validMcpLogLevels: McpLogLevel[] = [
    "debug",
    "info",
    "notice",
    "warning",
    "error",
    "crit",
    "alert",
    "emerg",
  ];
  const initialLogLevelConfig = config.logLevel;
  let validatedMcpLogLevel: McpLogLevel = "info"; // Default

  if (validMcpLogLevels.includes(initialLogLevelConfig as McpLogLevel)) {
    validatedMcpLogLevel = initialLogLevelConfig as McpLogLevel;
  } else {
    // Use console.warn here as logger isn't fully initialized yet, only if TTY
    if (process.stdout.isTTY) {
      console.warn(
        `Invalid MCP_LOG_LEVEL "${initialLogLevelConfig}" provided via config/env. Defaulting to "info".`,
      );
    }
  }
  // Initialize the logger with the validated MCP level and wait for it to complete.
  await logger.initialize(validatedMcpLogLevel);
  // The logger.initialize() method itself logs its status, so no redundant log here.
  // --- End Logger Initialization ---

  const configLoadContext = requestContextService.createRequestContext({
    operation: "ConfigLoad",
  });
  logger.debug("Configuration loaded successfully", {
    ...configLoadContext,
    configValues: config,
  }); // Spread context and add specific data

  const transportType = config.mcpTransportType;
  const startupContext = requestContextService.createRequestContext({
    operation: `AtlasServerStartup_${transportType}`,
    appName: config.mcpServerName,
    appVersion: config.mcpServerVersion,
    environment: environment,
  });

  logger.info(
    `Starting ${config.mcpServerName} v${config.mcpServerVersion} (Transport: ${transportType})...`,
    startupContext,
  );

  try {
    logger.debug(
      "Initializing and starting MCP server transport...",
      startupContext,
    );

    const potentialServer = await initializeAndStartServer();

    if (transportType === "stdio" && potentialServer instanceof McpServer) {
      serverInstance = potentialServer;
      logger.debug(
        "Stored McpServer instance for stdio transport.",
        startupContext,
      );
    } else if (transportType === "http" && potentialServer instanceof http.Server) {
      serverInstance = potentialServer;
      logger.debug(
        "Stored HTTP server instance. MCP sessions are per-request.",
        startupContext,
      );
    } else if (transportType === "http" && !potentialServer) {
        logger.debug(
            "HTTP transport started. Server instance not returned by initializeAndStartServer. MCP sessions are per-request.",
            startupContext,
        );
    }


    logger.info(
      `${config.mcpServerName} is running with ${transportType} transport.`,
      {
        ...startupContext,
        startTime: new Date().toISOString(),
      },
    );

    // --- Signal and Error Handling Setup ---
    process.on("SIGTERM", () => shutdown("SIGTERM"));
    process.on("SIGINT", () => shutdown("SIGINT"));

    process.on("uncaughtException", async (error) => {
      const errorContext = {
        ...startupContext,
        event: "uncaughtException",
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      };
      logger.error(
        "Uncaught exception detected. Initiating shutdown...",
        errorContext,
      );
      await shutdown("uncaughtException");
    });

    process.on("unhandledRejection", async (reason: unknown) => {
      const rejectionContext = {
        ...startupContext,
        event: "unhandledRejection",
        reason: reason instanceof Error ? reason.message : String(reason),
        stack: reason instanceof Error ? reason.stack : undefined,
      };
      logger.error(
        "Unhandled promise rejection detected. Initiating shutdown...",
        rejectionContext,
      );
      await shutdown("unhandledRejection");
    });
  } catch (error) {
    logger.error("Critical error during ATLAS MCP Server startup, exiting.", {
      ...startupContext,
      finalErrorContext: "Startup Failure",
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
    });
    process.exit(1);
  }
};

// --- Async IIFE to allow top-level await ---
(async () => {
  await start();
})();

```

--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_create/createProject.ts:
--------------------------------------------------------------------------------

```typescript
import { ProjectService } from "../../../services/neo4j/projectService.js";
import { ProjectDependencyType } from "../../../services/neo4j/types.js"; // Import the enum
import {
  BaseErrorCode,
  McpError,
  ProjectErrorCode,
} from "../../../types/errors.js";
import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { ToolContext } from "../../../types/tool.js";
import { AtlasProjectCreateInput, AtlasProjectCreateSchema } from "./types.js";
import { formatProjectCreateResponse } from "./responseFormat.js";

export const atlasCreateProject = async (
  input: unknown,
  context: ToolContext,
) => {
  let validatedInput: AtlasProjectCreateInput | undefined;
  const reqContext =
    context.requestContext ??
    requestContextService.createRequestContext({
      toolName: "atlasCreateProject",
    });

  try {
    // Parse and validate input against schema
    validatedInput = AtlasProjectCreateSchema.parse(input);

    // Handle single vs bulk project creation based on mode
    if (validatedInput.mode === "bulk") {
      // Execute bulk creation operation
      logger.info("Initializing multiple projects", {
        ...reqContext,
        count: validatedInput.projects.length,
      });

      const results = {
        success: true,
        message: `Successfully created ${validatedInput.projects.length} projects`,
        created: [] as any[],
        errors: [] as any[],
      };

      // Process each project sequentially to maintain consistency
      for (let i = 0; i < validatedInput.projects.length; i++) {
        const projectData = validatedInput.projects[i];
        try {
          const createdProject = await ProjectService.createProject({
            name: projectData.name,
            description: projectData.description,
            status: projectData.status || "active",
            urls: projectData.urls || [],
            completionRequirements: projectData.completionRequirements,
            outputFormat: projectData.outputFormat,
            taskType: projectData.taskType,
            id: projectData.id, // Use client-provided ID if available
          });

          results.created.push(createdProject);

          // Create dependency relationships if specified
          if (projectData.dependencies && projectData.dependencies.length > 0) {
            for (const dependencyId of projectData.dependencies) {
              try {
                await ProjectService.addProjectDependency(
                  createdProject.id,
                  dependencyId,
                  ProjectDependencyType.REQUIRES, // Use enum member
                  "Dependency created during project creation",
                );
              } catch (error) {
                const depErrorContext =
                  requestContextService.createRequestContext({
                    ...reqContext,
                    originalErrorMessage:
                      error instanceof Error ? error.message : String(error),
                    originalErrorStack:
                      error instanceof Error ? error.stack : undefined,
                    projectId: createdProject.id,
                    dependencyIdAttempted: dependencyId,
                  });
                logger.warning(
                  `Failed to create dependency for project ${createdProject.id} to ${dependencyId}`,
                  depErrorContext,
                );
              }
            }
          }
        } catch (error) {
          results.success = false;
          results.errors.push({
            index: i,
            project: projectData,
            error: {
              code:
                error instanceof McpError
                  ? error.code
                  : BaseErrorCode.INTERNAL_ERROR,
              message: error instanceof Error ? error.message : "Unknown error",
              details: error instanceof McpError ? error.details : undefined,
            },
          });
        }
      }

      if (results.errors.length > 0) {
        results.message = `Created ${results.created.length} of ${validatedInput.projects.length} projects with ${results.errors.length} errors`;
      }

      logger.info("Bulk project initialization completed", {
        ...reqContext,
        successCount: results.created.length,
        errorCount: results.errors.length,
        projectIds: results.created.map((p) => p.id),
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(results, null, 2));
      } else {
        return formatProjectCreateResponse(results);
      }
    } else {
      // Process single project creation
      const {
        mode,
        id,
        name,
        description,
        status,
        urls,
        completionRequirements,
        dependencies,
        outputFormat,
        taskType,
      } = validatedInput;

      logger.info("Initializing new project", {
        ...reqContext,
        name,
        status,
      });

      const project = await ProjectService.createProject({
        id, // Use client-provided ID if available
        name,
        description,
        status: status || "active",
        urls: urls || [],
        completionRequirements,
        outputFormat,
        taskType,
      });

      // Create dependency relationships if specified
      if (dependencies && dependencies.length > 0) {
        for (const dependencyId of dependencies) {
          try {
            await ProjectService.addProjectDependency(
              project.id,
              dependencyId,
              ProjectDependencyType.REQUIRES, // Use enum member
              "Dependency created during project creation",
            );
          } catch (error) {
            const depErrorContext = requestContextService.createRequestContext({
              ...reqContext,
              originalErrorMessage:
                error instanceof Error ? error.message : String(error),
              originalErrorStack:
                error instanceof Error ? error.stack : undefined,
              projectId: project.id,
              dependencyIdAttempted: dependencyId,
            });
            logger.warning(
              `Failed to create dependency for project ${project.id} to ${dependencyId}`,
              depErrorContext,
            );
          }
        }
      }

      logger.info("Project initialized successfully", {
        ...reqContext,
        projectId: project.id,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        return createToolResponse(JSON.stringify(project, null, 2));
      } else {
        return formatProjectCreateResponse(project);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

    logger.error("Failed to initialize project(s)", error as Error, {
      ...reqContext,
      inputReceived: validatedInput ?? input, // Log validated or raw input
    });

    // Handle duplicate name error specifically
    if (error instanceof Error && error.message.includes("duplicate")) {
      throw new McpError(
        ProjectErrorCode.DUPLICATE_NAME,
        `A project with this name already exists`,
        {
          name:
            validatedInput?.mode === "single"
              ? validatedInput?.name
              : validatedInput?.projects?.[0]?.name,
        },
      );
    }

    // Convert other errors to McpError
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Error creating project(s): ${error instanceof Error ? error.message : "Unknown error"}`,
    );
  }
};

```
Page 2/6FirstPrevNextLast