#
tokens: 49354/50000 22/146 files (page 3/6)
lines: off (toggle) GitHub
raw markdown copy
This is page 3 of 6. Use http://codebase.md/cyanheads/atlas-mcp-server?lines=false&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_update/types.ts:
--------------------------------------------------------------------------------

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

export const ProjectUpdateSchema = z.object({
  id: z.string().describe("Identifier of the existing project to be modified"),
  updates: z
    .object({
      name: z
        .string()
        .min(1)
        .max(100)
        .optional()
        .describe(
          "Modified project name following naming conventions (1-100 characters)",
        ),
      description: z
        .string()
        .optional()
        .describe("Revised project scope, goals, and implementation details"),
      status: z
        .enum([
          ProjectStatus.ACTIVE,
          ProjectStatus.PENDING,
          ProjectStatus.IN_PROGRESS,
          ProjectStatus.COMPLETED,
          ProjectStatus.ARCHIVED,
        ])
        .optional()
        .describe(
          "Updated lifecycle state reflecting current project progress",
        ),
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional()
        .describe(
          "Modified documentation links, specifications, and technical resources",
        ),
      completionRequirements: z
        .string()
        .optional()
        .describe(
          "Revised definition of done with updated success criteria and metrics",
        ),
      outputFormat: z
        .string()
        .optional()
        .describe("Modified deliverable specification for project artifacts"),
      taskType: z
        .enum([
          TaskType.RESEARCH,
          TaskType.GENERATION,
          TaskType.ANALYSIS,
          TaskType.INTEGRATION,
        ])
        .optional()
        .describe(
          "Revised classification for project categorization and workflow",
        ),
    })
    .describe(
      "Partial update object containing only fields that need modification",
    ),
});

const SingleProjectUpdateSchema = z
  .object({
    mode: z.literal("single"),
    id: z.string(),
    updates: z.object({
      name: z.string().min(1).max(100).optional(),
      description: z.string().optional(),
      status: z
        .enum([
          ProjectStatus.ACTIVE,
          ProjectStatus.PENDING,
          ProjectStatus.IN_PROGRESS,
          ProjectStatus.COMPLETED,
          ProjectStatus.ARCHIVED,
        ])
        .optional(),
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional(),
      completionRequirements: z.string().optional(),
      outputFormat: z.string().optional(),
      taskType: z
        .enum([
          TaskType.RESEARCH,
          TaskType.GENERATION,
          TaskType.ANALYSIS,
          TaskType.INTEGRATION,
        ])
        .optional(),
    }),
    responseFormat: createResponseFormatEnum()
      .optional()
      .default(ResponseFormat.FORMATTED)
      .describe(
        "Desired response format: 'formatted' (default string) or 'json' (raw object)",
      ),
  })
  .describe(
    "Atomically update a single project with selective field modifications",
  );

const BulkProjectUpdateSchema = z
  .object({
    mode: z.literal("bulk"),
    projects: z
      .array(
        z.object({
          id: z.string().describe("Identifier of the project to update"),
          updates: z.object({
            name: z.string().min(1).max(100).optional(),
            description: z.string().optional(),
            status: z
              .enum([
                ProjectStatus.ACTIVE,
                ProjectStatus.PENDING,
                ProjectStatus.IN_PROGRESS,
                ProjectStatus.COMPLETED,
                ProjectStatus.ARCHIVED,
              ])
              .optional(),
            urls: z
              .array(
                z.object({
                  title: z.string(),
                  url: z.string(),
                }),
              )
              .optional(),
            completionRequirements: z.string().optional(),
            outputFormat: z.string().optional(),
            taskType: z
              .enum([
                TaskType.RESEARCH,
                TaskType.GENERATION,
                TaskType.ANALYSIS,
                TaskType.INTEGRATION,
              ])
              .optional(),
          }),
        }),
      )
      .min(1)
      .max(100)
      .describe(
        "Collection of project 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 projects in a single efficient transaction",
  );

// Schema shapes for tool registration
export const AtlasProjectUpdateSchemaShape = {
  mode: z
    .enum(["single", "bulk"])
    .describe(
      "Operation mode - 'single' for individual update, 'bulk' for updating multiple projects",
    ),
  id: z
    .string()
    .optional()
    .describe(
      "Project identifier for the update operation (required for mode='single')",
    ),
  updates: z
    .object({
      name: z.string().min(1).max(100).optional(),
      description: z.string().optional(),
      status: z
        .enum([
          ProjectStatus.ACTIVE,
          ProjectStatus.PENDING,
          ProjectStatus.IN_PROGRESS,
          ProjectStatus.COMPLETED,
          ProjectStatus.ARCHIVED,
        ])
        .optional(),
      urls: z
        .array(
          z.object({
            title: z.string(),
            url: z.string(),
          }),
        )
        .optional(),
      completionRequirements: z.string().optional(),
      outputFormat: z.string().optional(),
      taskType: z
        .enum([
          TaskType.RESEARCH,
          TaskType.GENERATION,
          TaskType.ANALYSIS,
          TaskType.INTEGRATION,
        ])
        .optional(),
    })
    .optional()
    .describe(
      "Partial update specifying only the fields to be modified (required for mode='single')",
    ),
  projects: z
    .array(
      z.object({
        id: z.string(),
        updates: z.object({
          name: z.string().min(1).max(100).optional(),
          description: z.string().optional(),
          status: z
            .enum([
              ProjectStatus.ACTIVE,
              ProjectStatus.PENDING,
              ProjectStatus.IN_PROGRESS,
              ProjectStatus.COMPLETED,
              ProjectStatus.ARCHIVED,
            ])
            .optional(),
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .optional(),
          completionRequirements: z.string().optional(),
          outputFormat: z.string().optional(),
          taskType: z
            .enum([
              TaskType.RESEARCH,
              TaskType.GENERATION,
              TaskType.ANALYSIS,
              TaskType.INTEGRATION,
            ])
            .optional(),
        }),
      }),
    )
    .optional()
    .describe(
      "Collection of project modifications to apply in a single transaction (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 AtlasProjectUpdateSchema = z.discriminatedUnion("mode", [
  SingleProjectUpdateSchema,
  BulkProjectUpdateSchema,
]);

export type AtlasProjectUpdateInput = z.infer<typeof AtlasProjectUpdateSchema>;
export type ProjectUpdateInput = z.infer<typeof ProjectUpdateSchema>;
export type AtlasProjectUpdateResponse = McpToolResponse;

```

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

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import {
  PriorityLevel,
  ResponseFormat,
  TaskStatus,
  createResponseFormatEnum,
  createToolResponse,
} from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasListTasks } from "./listTasks.js";
import { formatTaskListResponse } from "./responseFormat.js";
import { TaskListRequestInput } from "./types.js"; // Corrected import

// Schema shapes for tool registration
const TaskListRequestSchemaShape = {
  projectId: z
    .string()
    .describe("ID of the project to list tasks for (required)"),
  status: z
    .union([
      z.enum([
        TaskStatus.BACKLOG,
        TaskStatus.TODO,
        TaskStatus.IN_PROGRESS,
        TaskStatus.COMPLETED,
      ]),
      z.array(
        z.enum([
          TaskStatus.BACKLOG,
          TaskStatus.TODO,
          TaskStatus.IN_PROGRESS,
          TaskStatus.COMPLETED,
        ]),
      ),
    ])
    .optional()
    .describe("Filter by task status or array of statuses"),
  assignedTo: z.string().optional().describe("Filter by assignment ID"),
  priority: z
    .union([
      z.enum([
        PriorityLevel.LOW,
        PriorityLevel.MEDIUM,
        PriorityLevel.HIGH,
        PriorityLevel.CRITICAL,
      ]),
      z.array(
        z.enum([
          PriorityLevel.LOW,
          PriorityLevel.MEDIUM,
          PriorityLevel.HIGH,
          PriorityLevel.CRITICAL,
        ]),
      ),
    ])
    .optional()
    .describe("Filter by priority level or array of priorities"),
  tags: z
    .array(z.string())
    .optional()
    .describe(
      "Array of tags to filter by (tasks matching any tag will be included)",
    ),
  taskType: z.string().optional().describe("Filter by task classification"),
  sortBy: z
    .enum(["priority", "createdAt", "status"])
    .optional()
    .describe("Field to sort results by (Default: createdAt)"),
  sortDirection: z
    .enum(["asc", "desc"])
    .optional()
    .describe("Sort order (Default: desc)"),
  page: z
    .number()
    .optional()
    .describe("Page number for paginated results (Default: 1)"),
  limit: z
    .number()
    .optional()
    .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)",
    ),
};

export const registerAtlasTaskListTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_task_list",
    "Lists tasks according to specified filters with advanced filtering, sorting, and pagination capabilities",
    TaskListRequestSchemaShape,
    async (input, context) => {
      // Parse and process input (assuming validation happens implicitly via registerTool)
      const validatedInput = input as unknown as TaskListRequestInput & {
        responseFormat?: ResponseFormat;
      }; // Corrected type cast
      const result = await atlasListTasks(validatedInput, context); // Added context argument

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        // Stringify the result and wrap it in a standard text response
        // The client will need to parse this stringified JSON
        return createToolResponse(JSON.stringify(result, null, 2));
      } else {
        // Return the formatted string using the formatter for rich display
        return formatTaskListResponse(result, false); // Added second argument
      }
    },
    createToolMetadata({
      examples: [
        createToolExample(
          {
            projectId: "proj_example123",
            status: "in_progress",
            limit: 10,
          },
          `{
            "tasks": [
              {
                "id": "task_abcd1234",
                "projectId": "proj_example123",
                "title": "Implement User Authentication",
                "description": "Create secure user authentication system with JWT and refresh tokens",
                "priority": "high",
                "status": "in_progress",
                "assignedTo": "user_5678",
                "tags": ["security", "backend"],
                "completionRequirements": "Authentication endpoints working with proper error handling and tests",
                "outputFormat": "Documented API with test coverage",
                "taskType": "implementation",
                "createdAt": "2025-03-20T14:24:35.123Z",
                "updatedAt": "2025-03-22T09:15:22.456Z"
              }
            ],
            "total": 5,
            "page": 1,
            "limit": 10,
            "totalPages": 1
          }`,
          "List in-progress tasks for a specific project",
        ),
        createToolExample(
          {
            projectId: "proj_frontend42",
            priority: ["high", "critical"],
            tags: ["bug", "urgent"],
            sortBy: "priority",
            sortDirection: "desc",
          },
          `{
            "tasks": [
              {
                "id": "task_ef5678",
                "projectId": "proj_frontend42",
                "title": "Fix Critical UI Rendering Bug",
                "description": "Address the UI rendering issue causing layout problems on mobile devices",
                "priority": "critical",
                "status": "todo",
                "tags": ["bug", "ui", "urgent"],
                "completionRequirements": "UI displays correctly on all supported mobile devices",
                "outputFormat": "Fixed code with browser compatibility tests",
                "taskType": "bugfix",
                "createdAt": "2025-03-21T10:30:15.789Z",
                "updatedAt": "2025-03-21T10:30:15.789Z"
              },
              {
                "id": "task_gh9012",
                "projectId": "proj_frontend42",
                "title": "Optimize Image Loading Performance",
                "description": "Implement lazy loading and optimize image assets to improve page load time",
                "priority": "high",
                "status": "backlog",
                "tags": ["performance", "urgent"],
                "completionRequirements": "Page load time reduced by 40% with Lighthouse score above 90",
                "outputFormat": "Optimized code with performance benchmarks",
                "taskType": "optimization",
                "createdAt": "2025-03-19T16:45:22.123Z",
                "updatedAt": "2025-03-19T16:45:22.123Z"
              }
            ],
            "total": 2,
            "page": 1,
            "limit": 20,
            "totalPages": 1
          }`,
          "List high priority and critical tasks with specific tags, sorted by priority",
        ),
      ],
      requiredPermission: "project:read",
      returnSchema: z.object({
        tasks: z.array(
          z.object({
            id: z.string(),
            projectId: z.string(),
            title: z.string(),
            description: z.string(),
            priority: z.enum([
              PriorityLevel.LOW,
              PriorityLevel.MEDIUM,
              PriorityLevel.HIGH,
              PriorityLevel.CRITICAL,
            ]),
            status: z.enum([
              TaskStatus.BACKLOG,
              TaskStatus.TODO,
              TaskStatus.IN_PROGRESS,
              TaskStatus.COMPLETED,
            ]),
            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(),
            outputFormat: z.string(),
            taskType: z.string(),
            createdAt: z.string(),
            updatedAt: z.string(),
          }),
        ),
        total: z.number().int(),
        page: z.number().int(),
        limit: z.number().int(),
        totalPages: z.number().int(),
      }),
      rateLimit: {
        windowMs: 60 * 1000, // 1 minute
        maxRequests: 30, // 30 requests per minute
      },
    }),
  );
};

```

--------------------------------------------------------------------------------
/scripts/fetch-openapi-spec.ts:
--------------------------------------------------------------------------------

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

/**
 * @fileoverview Fetches an OpenAPI specification (YAML/JSON) from a URL,
 * parses it, and saves it locally in both YAML and JSON formats.
 * @module scripts/fetch-openapi-spec
 *   Includes fallback logic for common OpenAPI file names (openapi.yaml, openapi.json).
 *   Ensures output paths are within the project directory for security.
 *
 * @example
 * // Fetch spec and save to docs/api/my_api.yaml and docs/api/my_api.json
 * // ts-node --esm scripts/fetch-openapi-spec.ts https://api.example.com/v1 docs/api/my_api
 *
 * @example
 * // Fetch spec from a direct file URL
 * // ts-node --esm scripts/fetch-openapi-spec.ts https://petstore3.swagger.io/api/v3/openapi.json docs/api/petstore_v3
 */

import axios, { AxiosError } from "axios";
import fs from "fs/promises";
import yaml from "js-yaml";
import path from "path";

const projectRoot = process.cwd();

const args = process.argv.slice(2);
const helpFlag = args.includes("--help");
const urlArg = args[0];
const outputBaseArg = args[1];

if (helpFlag || !urlArg || !outputBaseArg) {
  console.log(`
Fetch OpenAPI Specification Script

Usage:
  ts-node --esm scripts/fetch-openapi-spec.ts <url> <output-base-path> [--help]

Arguments:
  <url>                Base URL or direct URL to the OpenAPI spec (YAML/JSON).
  <output-base-path>   Base path for output files (relative to project root),
                       e.g., 'docs/api/my_api'. Will generate .yaml and .json.
  --help               Show this help message.

Example:
  ts-node --esm scripts/fetch-openapi-spec.ts https://petstore3.swagger.io/api/v3 docs/api/petstore_v3
`);
  process.exit(helpFlag ? 0 : 1);
}

const outputBasePathAbsolute = path.resolve(projectRoot, outputBaseArg);
const yamlOutputPath = `${outputBasePathAbsolute}.yaml`;
const jsonOutputPath = `${outputBasePathAbsolute}.json`;
const outputDirAbsolute = path.dirname(outputBasePathAbsolute);

// Security Check: Ensure output paths are within project root
if (
  !outputDirAbsolute.startsWith(projectRoot + path.sep) ||
  !yamlOutputPath.startsWith(projectRoot + path.sep) ||
  !jsonOutputPath.startsWith(projectRoot + path.sep)
) {
  console.error(
    `Error: Output path "${outputBaseArg}" resolves outside the project directory. Aborting.`,
  );
  process.exit(1);
}

/**
 * Attempts to fetch content from a given URL.
 * @param url - The URL to fetch data from.
 * @returns A promise resolving to an object with data and content type, or null if fetch fails.
 */
async function tryFetch(
  url: string,
): Promise<{ data: string; contentType: string | null } | null> {
  try {
    console.log(`Attempting to fetch from: ${url}`);
    const response = await axios.get(url, {
      responseType: "text",
      validateStatus: (status) => status >= 200 && status < 300,
    });
    const contentType = response.headers["content-type"] || null;
    console.log(
      `Successfully fetched (Status: ${response.status}, Content-Type: ${contentType || "N/A"})`,
    );
    return { data: response.data, contentType };
  } catch (error) {
    let status = "Unknown";
    if (axios.isAxiosError(error)) {
      const axiosError = error as AxiosError;
      status = axiosError.response
        ? String(axiosError.response.status)
        : "Network Error";
    }
    console.warn(`Failed to fetch from ${url} (Status: ${status})`);
    return null;
  }
}

/**
 * Parses fetched data as YAML or JSON, attempting to infer from content type or by trying both.
 * @param data - The raw string data fetched from the URL.
 * @param contentType - The content type header from the HTTP response, if available.
 * @returns The parsed OpenAPI specification as an object, or null if parsing fails.
 */
function parseSpec(data: string, contentType: string | null): object | null {
  try {
    const lowerContentType = contentType?.toLowerCase();
    if (
      lowerContentType?.includes("yaml") ||
      lowerContentType?.includes("yml")
    ) {
      console.log("Parsing content as YAML based on Content-Type...");
      return yaml.load(data) as object;
    } else if (lowerContentType?.includes("json")) {
      console.log("Parsing content as JSON based on Content-Type...");
      return JSON.parse(data);
    } else {
      console.log(
        "Content-Type is ambiguous or missing. Attempting to parse as YAML first...",
      );
      try {
        const parsedYaml = yaml.load(data) as object;
        // Basic validation: check if it's a non-null object.
        if (parsedYaml && typeof parsedYaml === "object") {
          console.log("Successfully parsed as YAML.");
          return parsedYaml;
        }
      } catch (yamlError) {
        console.log("YAML parsing failed. Attempting to parse as JSON...");
        try {
          const parsedJson = JSON.parse(data);
          if (parsedJson && typeof parsedJson === "object") {
            console.log("Successfully parsed as JSON.");
            return parsedJson;
          }
        } catch (jsonError) {
          console.warn(
            "Could not parse content as YAML or JSON after attempting both.",
          );
          return null;
        }
      }
      // If YAML parsing resulted in a non-object (e.g. string, number) but didn't throw
      console.warn(
        "Content parsed as YAML but was not a valid object structure. Trying JSON.",
      );
      try {
        const parsedJson = JSON.parse(data);
        if (parsedJson && typeof parsedJson === "object") {
          console.log(
            "Successfully parsed as JSON on second attempt for non-object YAML.",
          );
          return parsedJson;
        }
      } catch (jsonError) {
        console.warn(
          "Could not parse content as YAML or JSON after attempting both.",
        );
        return null;
      }
    }
  } catch (parseError) {
    console.error(
      `Error parsing specification: ${parseError instanceof Error ? parseError.message : String(parseError)}`,
    );
  }
  return null;
}

/**
 * Main orchestrator function. Fetches the OpenAPI spec from the provided URL (with fallbacks),
 * parses it, and saves it to the specified output paths in both YAML and JSON formats.
 */
async function fetchAndProcessSpec(): Promise<void> {
  let fetchedResult: { data: string; contentType: string | null } | null = null;
  const potentialUrls: string[] = [urlArg];

  if (
    !urlArg.endsWith(".yaml") &&
    !urlArg.endsWith(".yml") &&
    !urlArg.endsWith(".json")
  ) {
    const urlWithoutTrailingSlash = urlArg.endsWith("/")
      ? urlArg.slice(0, -1)
      : urlArg;
    potentialUrls.push(`${urlWithoutTrailingSlash}/openapi.yaml`);
    potentialUrls.push(`${urlWithoutTrailingSlash}/openapi.json`);
  }

  for (const url of potentialUrls) {
    fetchedResult = await tryFetch(url);
    if (fetchedResult) break;
  }

  if (!fetchedResult) {
    console.error(
      `Error: Failed to fetch specification from all attempted URLs: ${potentialUrls.join(", ")}. Aborting.`,
    );
    process.exit(1);
  }

  const openapiSpec = parseSpec(fetchedResult.data, fetchedResult.contentType);

  if (!openapiSpec || typeof openapiSpec !== "object") {
    console.error(
      "Error: Failed to parse specification content or content is not a valid object. Aborting.",
    );
    process.exit(1);
  }

  try {
    await fs.access(outputDirAbsolute);
  } catch (error: any) {
    if (error.code === "ENOENT") {
      console.log(`Output directory not found. Creating: ${outputDirAbsolute}`);
      await fs.mkdir(outputDirAbsolute, { recursive: true });
    } else {
      console.error(
        `Error accessing output directory ${outputDirAbsolute}: ${error.message}. Aborting.`,
      );
      process.exit(1);
    }
  }

  try {
    console.log(`Saving YAML specification to: ${yamlOutputPath}`);
    await fs.writeFile(yamlOutputPath, yaml.dump(openapiSpec), "utf8");
    console.log(`Successfully saved YAML specification.`);
  } catch (error) {
    console.error(
      `Error saving YAML to ${yamlOutputPath}: ${error instanceof Error ? error.message : String(error)}. Aborting.`,
    );
    process.exit(1);
  }

  try {
    console.log(`Saving JSON specification to: ${jsonOutputPath}`);
    await fs.writeFile(
      jsonOutputPath,
      JSON.stringify(openapiSpec, null, 2),
      "utf8",
    );
    console.log(`Successfully saved JSON specification.`);
  } catch (error) {
    console.error(
      `Error saving JSON to ${jsonOutputPath}: ${error instanceof Error ? error.message : String(error)}. Aborting.`,
    );
    process.exit(1);
  }

  console.log("OpenAPI specification processed and saved successfully.");
}

fetchAndProcessSpec();

```

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

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { ProjectStatus, createProjectStatusEnum } from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasUpdateProject } from "./updateProject.js";
import { AtlasProjectUpdateSchemaShape } from "./types.js";

export const registerAtlasProjectUpdateTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_project_update",
    "Modifies attributes of existing project entities within the system with support for both targeted single updates and efficient bulk modifications",
    AtlasProjectUpdateSchemaShape,
    atlasUpdateProject,
    createToolMetadata({
      examples: [
        createToolExample(
          {
            mode: "single",
            id: "proj_ms_migration",
            updates: {
              name: "Microservice Architecture Migration - Phase 2",
              description:
                "Extended refactoring to include data migration layer and enhanced service discovery through etcd integration",
              status: "in-progress",
            },
          },
          `{
            "id": "proj_ms_migration",
            "name": "Microservice Architecture Migration - Phase 2",
            "description": "Extended refactoring to include data migration layer and enhanced service discovery through etcd integration",
            "status": "in-progress",
            "urls": [
              {"title": "MCP Server Repository", "url": "https://github.com/cyanheads/atlas-mcp-server.git"},
              {"title": "Technical Spec", "url": "file:///Users/username/project_name/docs/atlas-reference.md"},
              {"title": "MCP Docs", "url": "https://modelcontextprotocol.io/"}
            ],
            "completionRequirements": "All critical services migrated with 100% test coverage, performance metrics meeting SLAs, and zero regressions in core functionality",
            "outputFormat": "Containerized services with CI/CD pipelines, comprehensive API documentation, and migration runbook",
            "taskType": "integration",
            "createdAt": "2025-03-23T10:11:24.123Z",
            "updatedAt": "2025-03-23T10:12:34.456Z"
          }`,
          "Update project scope and phase for an ongoing engineering initiative",
        ),
        createToolExample(
          {
            mode: "bulk",
            projects: [
              {
                id: "proj_graphql",
                updates: {
                  status: "completed",
                  completionRequirements:
                    "API supports all current use cases with n+1 query optimization, proper error handling, and 95% test coverage with performance benchmarks showing 30% reduction in API request times",
                },
              },
              {
                id: "proj_perf",
                updates: {
                  status: "in-progress",
                  description:
                    "Extended performance analysis to include bundle size optimization, lazy-loading routes, and server-side rendering for critical pages",
                  urls: [
                    {
                      title: "Lighthouse CI Results",
                      url: "https://lighthouse-ci.app/dashboard?project=frontend-perf",
                    },
                    {
                      title: "Web Vitals Tracking",
                      url: "https://analytics.google.com/web-vitals",
                    },
                  ],
                },
              },
            ],
          },
          `{
            "success": true,
            "message": "Successfully updated 2 projects",
            "updated": [
              {
                "id": "proj_graphql",
                "name": "GraphQL API Implementation",
                "description": "Design and implement GraphQL API layer to replace existing REST endpoints with optimized query capabilities",
                "status": "completed",
                "urls": [],
                "completionRequirements": "API supports all current use cases with n+1 query optimization, proper error handling, and 95% test coverage with performance benchmarks showing 30% reduction in API request times",
                "outputFormat": "TypeScript-based GraphQL schema with resolvers, documentation, and integration tests",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.123Z",
                "updatedAt": "2025-03-23T10:12:34.456Z"
              },
              {
                "id": "proj_perf",
                "name": "Performance Optimization Suite",
                "description": "Extended performance analysis to include bundle size optimization, lazy-loading routes, and server-side rendering for critical pages",
                "status": "in-progress",
                "urls": [
                  {"title": "Lighthouse CI Results", "url": "https://lighthouse-ci.app/dashboard?project=frontend-perf"},
                  {"title": "Web Vitals Tracking", "url": "https://analytics.google.com/web-vitals"}
                ],
                "completionRequirements": "Core React components meet Web Vitals thresholds with 50% reduction in LCP and TTI metrics",
                "outputFormat": "Optimized component library, performance test suite, and technical recommendation document",
                "taskType": "analysis",
                "createdAt": "2025-03-23T10:11:24.456Z",
                "updatedAt": "2025-03-23T10:12:34.789Z"
              }
            ],
            "errors": []
          }`,
          "Synchronize project statuses across dependent engineering initiatives",
        ),
      ],
      requiredPermission: "project:update",
      returnSchema: z.union([
        // Single project response
        z.object({
          id: z.string().describe("Project ID"),
          name: z.string().describe("Project name"),
          description: z.string().describe("Project description"),
          status: createProjectStatusEnum().describe("Project status"),
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .describe("Reference materials"),
          completionRequirements: z.string().describe("Completion criteria"),
          outputFormat: z.string().describe("Deliverable format"),
          taskType: z.string().describe("Project classification"),
          createdAt: z.string().describe("Creation timestamp"),
          updatedAt: z.string().describe("Last update timestamp"),
        }),
        // Bulk update response
        z.object({
          success: z.boolean().describe("Operation success status"),
          message: z.string().describe("Result message"),
          updated: z
            .array(
              z.object({
                id: z.string().describe("Project ID"),
                name: z.string().describe("Project name"),
                description: z.string().describe("Project description"),
                status: createProjectStatusEnum().describe("Project status"),
                urls: z
                  .array(
                    z.object({
                      title: z.string(),
                      url: z.string(),
                    }),
                  )
                  .describe("Reference materials"),
                completionRequirements: z
                  .string()
                  .describe("Completion criteria"),
                outputFormat: z.string().describe("Deliverable format"),
                taskType: z.string().describe("Project classification"),
                createdAt: z.string().describe("Creation timestamp"),
                updatedAt: z.string().describe("Last update timestamp"),
              }),
            )
            .describe("Updated projects"),
          errors: z
            .array(
              z.object({
                index: z.number().describe("Index in the projects array"),
                project: z.any().describe("Original project update 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("Update errors"),
        }),
      ]),
      rateLimit: {
        windowMs: 60 * 1000, // 1 minute
        maxRequests: 15, // 15 requests per minute (either single or bulk)
      },
    }),
  );
};

```

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

```css
/* ==========================================================================
   Component Styles: Buttons, Selects, Cards, Toggles etc.
   ========================================================================== */
select,
button {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--border-radius-md);
  border: 1px solid var(--border-color);
  font-size: 1rem;
  background-color: var(--card-bg-color); /* Match card for consistency */
  color: var(--text-color);
  transition:
    background-color 0.15s ease-out,
    border-color 0.15s ease-out,
    box-shadow 0.15s ease-out;
}

select:focus,
button:focus {
  outline: none;
  border-color: var(--primary-color);
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25); /* Standard Bootstrap-like focus ring */
}
/* For dark mode, ensure focus ring is visible */
.dark-mode select:focus,
.dark-mode button:focus {
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.35);
}

select {
  flex-grow: 1;
  min-width: 200px; /* Ensure select has a minimum width */
}

button {
  background-color: var(--primary-color);
  color: var(--button-text-color);
  cursor: pointer;
  font-weight: 500;
  border-color: var(--primary-color);
}

button:hover {
  background-color: var(--primary-hover-color);
  border-color: var(--primary-hover-color);
}

button#refresh-button {
  background-color: var(--button-secondary-bg);
  border-color: var(--button-secondary-bg);
  color: var(--button-text-color);
}
button#refresh-button:hover {
  background-color: var(--button-secondary-hover-bg);
  border-color: var(--button-secondary-hover-bg);
}

.view-controls {
  display: flex;
  gap: var(--spacing-sm);
}

.view-controls .view-toggle-button {
  padding: var(--spacing-xs) var(--spacing-sm);
  font-size: 0.85rem;
  background-color: transparent;
  color: var(--primary-color);
  border: 1px solid var(--primary-color);
}
.view-controls .view-toggle-button:hover,
.view-controls .view-toggle-button:focus {
  background-color: rgba(
    0,
    123,
    255,
    0.1
  ); /* Use primary color with alpha for hover */
}
.dark-mode .view-controls .view-toggle-button:hover,
.dark-mode .view-controls .view-toggle-button:focus {
  background-color: rgba(
    0,
    123,
    255,
    0.2
  ); /* Slightly more opaque for dark mode */
}

/* Compact View for Tasks/Knowledge */
.data-item.compact {
  padding: var(--spacing-sm) 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.data-item.compact strong {
  margin-bottom: 0;
  font-weight: 500;
}
.data-item.compact .item-status {
  font-size: 0.85rem;
  color: var(--secondary-text-color);
  background-color: var(--code-bg-color);
  padding: 2px 6px;
  border-radius: var(--border-radius-sm);
}
/* Hide detailed elements in compact mode */
.data-item.compact pre, 
.data-item.compact div:not(:first-child), /* Hides divs other than the one containing the title/status */
.data-item.compact ul {
  display: none;
}

.task-card {
  background-color: var(--card-bg-color);
  padding: var(--spacing-sm);
  border-radius: var(--border-radius-sm);
  border: 1px solid var(--data-item-border-color);
  box-shadow: 0 2px 4px var(--shadow-color);
  cursor: pointer; /* If tasks are clickable for details */
  transition:
    box-shadow 0.15s ease-out,
    transform 0.15s ease-out;
}

.task-card:hover {
  box-shadow: 0 4px 8px var(--shadow-color);
  transform: translateY(-2px);
}

.task-card-title {
  font-weight: 600;
  margin-bottom: var(--spacing-xs);
  color: var(--text-color);
}

.task-card-priority,
.task-card-assignee {
  font-size: 0.8rem;
  color: var(--secondary-text-color);
  margin-top: var(--spacing-xs);
}

.empty-column {
  text-align: center;
  color: var(--secondary-text-color);
  font-style: italic;
  padding: var(--spacing-md) 0;
}

.explorer-node-item {
  padding: var(--spacing-sm);
  border-bottom: 1px solid var(--data-item-border-color);
  cursor: pointer;
  transition: background-color 0.15s ease-out;
}

.explorer-node-item:last-child {
  border-bottom: none;
}

.explorer-node-item:hover {
  background-color: var(--bg-color); /* Subtle hover effect */
}
.dark-mode .explorer-node-item:hover {
  background-color: var(--border-color); /* Darker hover for dark mode */
}

/* ==========================================================================
   Status, Error, Loading Messages
   ========================================================================== */
.error {
  /* For #error-message div */
  color: var(--error-color);
  font-weight: 500;
  padding: var(--spacing-sm) var(--spacing-md);
  background-color: var(--error-bg-color);
  border: 1px solid var(--error-border-color);
  border-radius: var(--border-radius-sm);
  margin-top: var(--spacing-md);
  transition:
    background-color 0.2s ease-out,
    border-color 0.2s ease-out,
    color 0.2s ease-out;
}

.loading {
  /* For loading text within containers */
  font-style: italic;
  color: var(--secondary-text-color);
  padding: var(--spacing-md) 0;
  text-align: center;
}

#connection-status {
  margin-top: var(
    --spacing-lg
  ); /* Ensure it's below error message if both visible */
  padding: var(--spacing-sm) var(--spacing-md);
  background-color: var(--connection-status-bg);
  border-radius: var(--border-radius-sm);
  text-align: center;
  font-weight: 500;
  color: var(--text-color);
  transition:
    background-color 0.2s ease-out,
    color 0.2s ease-out;
}
#connection-status span {
  /* The actual status text, e.g., "Connected" */
  font-weight: 600;
}

/* ==========================================================================
   Utility Classes
   ========================================================================== */
.hidden {
  display: none !important;
}

/* ==========================================================================
   Theme Toggle Switch
   ========================================================================== */
.theme-switch-wrapper {
  display: flex;
  align-items: center;
  position: absolute;
  top: var(--spacing-md);
  right: var(--spacing-md);
  gap: var(--spacing-sm);
}
.theme-label {
  font-size: 0.8rem;
  color: var(--secondary-text-color);
  cursor: pointer;
}

.theme-switch {
  /* The label acting as a container */
  display: inline-block;
  height: 20px; /* Smaller toggle */
  position: relative;
  width: 40px; /* Smaller toggle */
}
.theme-switch input {
  display: none;
} /* Hide actual checkbox */

.slider {
  /* The visual track of the switch */
  background-color: #ccc; /* Default off state */
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  transition: 0.3s;
  border-radius: 20px; /* Fully rounded ends */
}
.slider:before {
  /* The circular handle */
  background-color: #fff;
  position: absolute;
  content: "";
  height: 14px; /* Smaller handle */
  width: 14px; /* Smaller handle */
  left: 3px; /* Padding from left edge */
  bottom: 3px; /* Padding from bottom edge */
  transition: 0.3s;
  border-radius: 50%; /* Circular */
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

input:checked + .slider {
  background-color: var(--primary-color);
} /* "On" state color */
input:checked + .slider:before {
  transform: translateX(20px);
} /* Move handle to the right */

/* ==========================================================================
   Responsive Adjustments
   ========================================================================== */
@media (max-width: 768px) {
  body {
    font-size: 15px;
  }
  #app {
    margin: var(--spacing-md);
    padding: var(--spacing-md);
  }
  h1 {
    font-size: 1.8rem;
  }
  h2 {
    font-size: 1.5rem;
  }
  h3 {
    font-size: 1.2rem;
  }

  .controls-container {
    flex-direction: column;
    align-items: stretch; /* Make controls full width */
  }
  .controls-container select,
  .controls-container button {
    width: 100%;
    margin-bottom: var(--spacing-sm); /* Consistent spacing when stacked */
  }
  .controls-container button:last-child {
    margin-bottom: 0;
  }

  .section-header {
    flex-direction: column;
    align-items: flex-start; /* Align header content to the start */
  }
  .view-controls {
    width: 100%;
    justify-content: flex-start; /* Align toggles to start */
  }

  .theme-switch-wrapper {
    top: var(--spacing-sm);
    right: var(--spacing-sm);
  }
  .theme-label {
    display: none; /* Hide "Toggle Theme" text on small screens to save space */
  }

  #details-content.details-grid {
    grid-template-columns: 1fr; /* Stack labels and values */
  }
  #details-content.details-grid > .data-item > strong {
    /* Label */
    margin-bottom: var(
      --spacing-xs
    ); /* Space between label and value when stacked */
    grid-column: 1; /* Ensure it stays in the first column */
  }
  #details-content.details-grid > .data-item > div,
  #details-content.details-grid > .data-item > pre,
  #details-content.details-grid > .data-item > ul {
    /* Value */
    grid-column: 1; /* Ensure it stays in the first column */
  }
}

```

--------------------------------------------------------------------------------
/src/mcp/transports/authentication/authMiddleware.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview MCP Authentication Middleware for Bearer Token Validation (JWT).
 *
 * This middleware validates JSON Web Tokens (JWT) passed via the 'Authorization' header
 * using the 'Bearer' scheme (e.g., "Authorization: Bearer <your_token>").
 * It verifies the token's signature and expiration using the secret key defined
 * in the configuration (`config.mcpAuthSecretKey`).
 *
 * If the token is valid, an object conforming to the MCP SDK's `AuthInfo` type
 * (expected to contain `token`, `clientId`, and `scopes`) is attached to `req.auth`.
 * If the token is missing, invalid, or expired, it sends an HTTP 401 Unauthorized response.
 *
 * @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
 * @module src/mcp-server/transports/authentication/authMiddleware
 */

import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js"; // Import from SDK
import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
import { config, environment } from "../../../config/index.js";
import { logger, requestContextService } from "../../../utils/index.js";

// Extend the Express Request interface to include the optional 'auth' property
// using the imported AuthInfo type from the SDK.
declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace Express {
    interface Request {
      /** Authentication information derived from the JWT, conforming to MCP SDK's AuthInfo. */
      auth?: AuthInfo;
    }
  }
}

// Startup Validation: Validate secret key presence on module load.
if (environment === "production" && !config.mcpAuthSecretKey) {
  logger.fatal(
    "CRITICAL: MCP_AUTH_SECRET_KEY is not set in production environment. Authentication cannot proceed securely.",
  );
  throw new Error(
    "MCP_AUTH_SECRET_KEY must be set in production environment for JWT authentication.",
  );
} else if (!config.mcpAuthSecretKey) {
  logger.warning(
    "MCP_AUTH_SECRET_KEY is not set. Authentication middleware will bypass checks (DEVELOPMENT ONLY). This is insecure for production.",
  );
}

/**
 * Express middleware for verifying JWT Bearer token authentication.
 */
export function mcpAuthMiddleware(
  req: Request,
  res: Response,
  next: NextFunction,
): void {
  const context = requestContextService.createRequestContext({
    operation: "mcpAuthMiddleware",
    method: req.method,
    path: req.path,
  });
  logger.debug(
    "Running MCP Authentication Middleware (Bearer Token Validation)...",
    context,
  );

  // Development Mode Bypass
  if (!config.mcpAuthSecretKey) {
    if (environment !== "production") {
      logger.warning(
        "Bypassing JWT authentication: MCP_AUTH_SECRET_KEY is not set (DEVELOPMENT ONLY).",
        context,
      );
      // Populate req.auth strictly according to SDK's AuthInfo
      req.auth = {
        token: "dev-mode-placeholder-token",
        clientId: "dev-client-id",
        scopes: ["dev-scope"],
      };
      // Log dev mode details separately, not attaching to req.auth if not part of AuthInfo
      logger.debug("Dev mode auth object created.", {
        ...context,
        authDetails: req.auth,
      });
      return next();
    } else {
      logger.error(
        "FATAL: MCP_AUTH_SECRET_KEY is missing in production. Cannot bypass auth.",
        context,
      );
      res.status(500).json({
        error: "Server configuration error: Authentication key missing.",
      });
      return;
    }
  }

  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    logger.warning(
      "Authentication failed: Missing or malformed Authorization header (Bearer scheme required).",
      context,
    );
    res.status(401).json({
      error: "Unauthorized: Missing or invalid authentication token format.",
    });
    return;
  }

  const tokenParts = authHeader.split(" ");
  if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer" || !tokenParts[1]) {
    logger.warning("Authentication failed: Malformed Bearer token.", context);
    res
      .status(401)
      .json({ error: "Unauthorized: Malformed authentication token." });
    return;
  }
  const rawToken = tokenParts[1];

  try {
    const decoded = jwt.verify(rawToken, config.mcpAuthSecretKey);

    if (typeof decoded === "string") {
      logger.warning(
        "Authentication failed: JWT decoded to a string, expected an object payload.",
        context,
      );
      res
        .status(401)
        .json({ error: "Unauthorized: Invalid token payload format." });
      return;
    }

    // Extract and validate fields for SDK's AuthInfo
    const clientIdFromToken =
      typeof decoded.cid === "string"
        ? decoded.cid
        : typeof decoded.client_id === "string"
          ? decoded.client_id
          : undefined;
    if (!clientIdFromToken) {
      logger.warning(
        "Authentication failed: JWT 'cid' or 'client_id' claim is missing or not a string.",
        { ...context, jwtPayloadKeys: Object.keys(decoded) },
      );
      res.status(401).json({
        error: "Unauthorized: Invalid token, missing client identifier.",
      });
      return;
    }

    let scopesFromToken: string[];
    if (
      Array.isArray(decoded.scp) &&
      decoded.scp.every((s) => typeof s === "string")
    ) {
      scopesFromToken = decoded.scp as string[];
    } else if (
      typeof decoded.scope === "string" &&
      decoded.scope.trim() !== ""
    ) {
      scopesFromToken = decoded.scope.split(" ").filter((s) => s);
      if (scopesFromToken.length === 0 && decoded.scope.trim() !== "") {
        // handles case " " -> [""]
        scopesFromToken = [decoded.scope.trim()];
      } else if (scopesFromToken.length === 0 && decoded.scope.trim() === "") {
        // If scope is an empty string, treat as no scopes.
        // This will now lead to an error if scopes are considered mandatory.
        logger.debug(
          "JWT 'scope' claim was an empty string, resulting in empty scopes array.",
          context,
        );
      }
    } else {
      // If scopes are strictly mandatory and not found or invalid format
      logger.warning(
        "Authentication failed: JWT 'scp' or 'scope' claim is missing, not an array of strings, or not a valid space-separated string.",
        { ...context, jwtPayloadKeys: Object.keys(decoded) },
      );
      res.status(401).json({
        error: "Unauthorized: Invalid token, missing or invalid scopes.",
      });
      return;
    }

    // If, after parsing, scopesFromToken is empty and scopes are considered mandatory for any operation.
    // This check assumes that all valid tokens must have at least one scope.
    // If some tokens are legitimately allowed to have no scopes for certain operations,
    // this check might need to be adjusted or handled downstream.
    if (scopesFromToken.length === 0) {
      logger.warning(
        "Authentication failed: Token resulted in an empty scope array, and scopes are required.",
        { ...context, jwtPayloadKeys: Object.keys(decoded) },
      );
      res.status(401).json({
        error: "Unauthorized: Token must contain valid, non-empty scopes.",
      });
      return;
    }

    // Construct req.auth with only the properties defined in SDK's AuthInfo
    // All other claims from 'decoded' are not part of req.auth for type safety.
    req.auth = {
      token: rawToken,
      clientId: clientIdFromToken,
      scopes: scopesFromToken,
    };

    // Log separately if other JWT claims like 'sub' (sessionId) are needed for app logic
    const subClaimForLogging =
      typeof decoded.sub === "string" ? decoded.sub : undefined;
    logger.debug("JWT verified successfully. AuthInfo attached to request.", {
      ...context,
      mcpSessionIdContext: subClaimForLogging,
      clientId: req.auth.clientId,
      scopes: req.auth.scopes,
    });
    next();
  } catch (error: unknown) {
    let errorMessage = "Invalid token";
    if (error instanceof jwt.TokenExpiredError) {
      errorMessage = "Token expired";
      logger.warning("Authentication failed: Token expired.", {
        ...context,
        expiredAt: error.expiredAt,
      });
    } else if (error instanceof jwt.JsonWebTokenError) {
      errorMessage = `Invalid token: ${error.message}`;
      logger.warning(`Authentication failed: ${errorMessage}`, { ...context });
    } else if (error instanceof Error) {
      errorMessage = `Verification error: ${error.message}`;
      logger.error(
        "Authentication failed: Unexpected error during token verification.",
        { ...context, error: error.message },
      );
    } else {
      errorMessage = "Unknown verification error";
      logger.error(
        "Authentication failed: Unexpected non-error exception during token verification.",
        { ...context, error },
      );
    }
    res.status(401).json({ error: `Unauthorized: ${errorMessage}.` });
  }
}

```

--------------------------------------------------------------------------------
/examples/backup-example/relationships.json:
--------------------------------------------------------------------------------

```json
[
  {
    "startNodeId": "know_8edd2c00340b4959b5dd7bd493484a78",
    "endNodeId": "cite_575e1e35306748cf92c76825c093da8c",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_8edd2c00340b4959b5dd7bd493484a78",
    "endNodeId": "cite_595e7750df1e473289e4dd2439df5671",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_8edd2c00340b4959b5dd7bd493484a78",
    "endNodeId": "cite_119039866696470493f9547fe5cd072e",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_8edd2c00340b4959b5dd7bd493484a78",
    "endNodeId": "cite_c52fc132a7714274bf81ab6108b81700",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_ea8b3222e36d4e26b73a0d865312413f",
    "endNodeId": "cite_877e56d5c98f48e99776b81c8820a171",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_ea8b3222e36d4e26b73a0d865312413f",
    "endNodeId": "cite_9886a57991f542738b0b239e86f0cb5b",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_ea8b3222e36d4e26b73a0d865312413f",
    "endNodeId": "cite_1d64e2512f8c455e9ba902f1d1c7e60d",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "task_5d3304ef2c9c4d6b9288fea38ed6ba84",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_fdfd015829824c42b3085605550ebff0",
      "createdAt": "2025-03-26T18:40:55.603Z"
    }
  },
  {
    "startNodeId": "task_4a224bcddf5246afaa732834d84b4b73",
    "endNodeId": "task_4da902b4e18a46c4b5b5d1043c7d0665",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_b40da62436794468b489040802ba8492",
      "createdAt": "2025-03-26T18:40:19.614Z"
    }
  },
  {
    "startNodeId": "task_3f5dd265abf04cc3983550a7b2a5f7fd",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_e707d3e3d21c4de89a7a5880a29864b3",
      "createdAt": "2025-03-26T18:40:46.252Z"
    }
  },
  {
    "startNodeId": "task_fba80d348f274e908de4ee988df754cc",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_6a0183a939a5404dbbfa57c042b1a72c",
      "createdAt": "2025-03-26T18:40:29.392Z"
    }
  },
  {
    "startNodeId": "task_0fa6a009306b41108f5292475754c33a",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_ff36bf29d5144c86af9e0e10a1a93d01",
      "createdAt": "2025-03-26T18:40:37.820Z"
    }
  },
  {
    "startNodeId": "task_30dc34e190cf4c6690e8e4002269b8d5",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_7fdd83efc94446eb9511cd13c0d2f8f3",
      "createdAt": "2025-03-26T18:41:03.780Z"
    }
  },
  {
    "startNodeId": "know_1d9b88ea4f2f448c926382e7d899a27c",
    "endNodeId": "cite_0fdaff7b58d044d4a9a4ec8445c1f334",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_1d9b88ea4f2f448c926382e7d899a27c",
    "endNodeId": "cite_74b89ff0621743babbb520d6b3728c2c",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_1d9b88ea4f2f448c926382e7d899a27c",
    "endNodeId": "cite_67c17ede43d54a6d9126395922136c6d",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_5894c5e7cd674206b82470c4d46265e7",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_1d9b88ea4f2f448c926382e7d899a27c",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_8edd2c00340b4959b5dd7bd493484a78",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_ea8b3222e36d4e26b73a0d865312413f",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_24f1739b78e1430e90a89cfe6c208d63",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_b3881c98f99c41a0992686aee015ad57",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_111b5c3bbc3d416883aab006ac1b8f2c",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "know_c9ebf9d01d0841b28fbdfc508a3754ef",
    "type": "CONTAINS_KNOWLEDGE",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_30dc34e190cf4c6690e8e4002269b8d5",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_5d3304ef2c9c4d6b9288fea38ed6ba84",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_3f5dd265abf04cc3983550a7b2a5f7fd",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_0fa6a009306b41108f5292475754c33a",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_fba80d348f274e908de4ee988df754cc",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_4a224bcddf5246afaa732834d84b4b73",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_4da902b4e18a46c4b5b5d1043c7d0665",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "portfolio-main",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "CONTAINS_TASK",
    "properties": {}
  },
  {
    "startNodeId": "task_4da902b4e18a46c4b5b5d1043c7d0665",
    "endNodeId": "task_ac11f7a5f83c4f339cae63de850ecda6",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_421a11c847ca4882b230bc1642b58787",
      "createdAt": "2025-03-26T18:40:12.040Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_30dc34e190cf4c6690e8e4002269b8d5",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_aef200e791fe4bbc8b91c08ea85d7a28",
      "createdAt": "2025-03-26T18:41:18.406Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_5d3304ef2c9c4d6b9288fea38ed6ba84",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_b92de5768b50443ebbebf21d2f430ef4",
      "createdAt": "2025-03-26T18:41:18.396Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_3f5dd265abf04cc3983550a7b2a5f7fd",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_f8aaf167d5d647b9b55deb3238e1c43f",
      "createdAt": "2025-03-26T18:41:18.386Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_0fa6a009306b41108f5292475754c33a",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_96305fbfb61c4865bb86dcc8aa465397",
      "createdAt": "2025-03-26T18:41:18.371Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_fba80d348f274e908de4ee988df754cc",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_de6d7c885c8445578b1a3bfa45659ecf",
      "createdAt": "2025-03-26T18:41:18.362Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_4a224bcddf5246afaa732834d84b4b73",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_f547fbd917ca4f3284094281bed0cf39",
      "createdAt": "2025-03-26T18:41:18.352Z"
    }
  },
  {
    "startNodeId": "task_3e955c8424fa48dbb6e9bcc27c0bed92",
    "endNodeId": "task_4da902b4e18a46c4b5b5d1043c7d0665",
    "type": "DEPENDS_ON",
    "properties": {
      "id": "tdep_422dbc91eaca4a3c9fc4f52f18893914",
      "createdAt": "2025-03-26T18:41:18.342Z"
    }
  },
  {
    "startNodeId": "know_b3881c98f99c41a0992686aee015ad57",
    "endNodeId": "cite_a77ccf2317c84c15b572ee8bc565c7f9",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_b3881c98f99c41a0992686aee015ad57",
    "endNodeId": "cite_a8e6328e26cf45aeaf058671f49e23ed",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_24f1739b78e1430e90a89cfe6c208d63",
    "endNodeId": "cite_8cb216010e734c5ab9c897e289989b8c",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_24f1739b78e1430e90a89cfe6c208d63",
    "endNodeId": "cite_137a7d753f044d06868b5758fa22433e",
    "type": "CITES",
    "properties": {}
  },
  {
    "startNodeId": "know_24f1739b78e1430e90a89cfe6c208d63",
    "endNodeId": "cite_bcf2dd0751404fd4b8aceba3d6d14871",
    "type": "CITES",
    "properties": {}
  }
]

```

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

```typescript
/**
 * Main entry point for the MCP (Model Context Protocol) server.
 * This file orchestrates the server's lifecycle:
 * 1. Initializes the core McpServer instance with its identity and capabilities.
 * 2. Registers available resources and tools, making them discoverable and usable by clients.
 * 3. Selects and starts the appropriate communication transport (stdio or Streamable HTTP)
 *    based on configuration.
 * 4. Handles top-level error management during startup.
 *
 * MCP Specification References:
 * - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
 * - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
 * - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
 */

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import http from "http";
// Import validated configuration and environment details.
import { config, environment } from "../config/index.js";
// Import core utilities: ErrorHandler, logger, requestContextService.
import { initializeNeo4jSchema } from "../services/neo4j/index.js"; // Corrected path
import { ErrorHandler, logger, requestContextService } from "../utils/index.js"; // Corrected path

// Import tool registrations
import { registerAtlasDatabaseCleanTool } from "./tools/atlas_database_clean/index.js";
import { registerAtlasDeepResearchTool } from "./tools/atlas_deep_research/index.js";
import { registerAtlasKnowledgeAddTool } from "./tools/atlas_knowledge_add/index.js";
import { registerAtlasKnowledgeDeleteTool } from "./tools/atlas_knowledge_delete/index.js";
import { registerAtlasKnowledgeListTool } from "./tools/atlas_knowledge_list/index.js";
import { registerAtlasProjectCreateTool } from "./tools/atlas_project_create/index.js";
import { registerAtlasProjectDeleteTool } from "./tools/atlas_project_delete/index.js";
import { registerAtlasProjectListTool } from "./tools/atlas_project_list/index.js";
import { registerAtlasProjectUpdateTool } from "./tools/atlas_project_update/index.js";
import { registerAtlasTaskCreateTool } from "./tools/atlas_task_create/index.js";
import { registerAtlasTaskDeleteTool } from "./tools/atlas_task_delete/index.js";
import { registerAtlasTaskListTool } from "./tools/atlas_task_list/index.js";
import { registerAtlasTaskUpdateTool } from "./tools/atlas_task_update/index.js";
import { registerAtlasUnifiedSearchTool } from "./tools/atlas_unified_search/index.js";

// Import resource registrations
import { registerMcpResources } from "./resources/index.js"; // Adjusted path

// Import transport setup functions.
import { startHttpTransport } from "./transports/httpTransport.js";
import { connectStdioTransport } from "./transports/stdioTransport.js";

/**
 * Creates and configures a new instance of the McpServer.
 *
 * This function is central to defining the server's identity and functionality
 * as presented to connecting clients during the MCP initialization phase.
 */
async function createMcpServerInstance(): Promise<McpServer> {
  const context = requestContextService.createRequestContext({
    operation: "createMcpServerInstance",
  });
  logger.info("Initializing MCP server instance for ATLAS MCP Server", context);

  // Configure the request context service (used for correlating logs/errors).
  requestContextService.configure({
    appName: config.mcpServerName,
    appVersion: config.mcpServerVersion,
    environment,
  });

  // Initialize Neo4j database and services
  logger.info("Initializing Neo4j schema...", context);
  await initializeNeo4jSchema();
  logger.info("Neo4j schema initialized successfully", context);

  // Instantiate the core McpServer using the SDK.
  logger.debug("Instantiating McpServer with capabilities", {
    ...context,
    serverInfo: {
      name: config.mcpServerName,
      version: config.mcpServerVersion,
    },
    capabilities: {
      logging: {}, // Indicates support for logging control and notifications
      resources: { listChanged: true }, // Supports dynamic resource lists
      tools: {
        listChanged: true, // Supports dynamic tool lists
        requestContext: true, // Enable request context for all tools
        rateLimit: {
          // Default rate limit settings for tools
          windowMs: config.security.rateLimitWindowMs || 60 * 1000, // Use config or default
          maxRequests: config.security.rateLimitMaxRequests || 100, // Use config or default
        },
        permissions: {
          // Permissions requirements for tools
          required: config.security.authRequired,
        },
      },
    },
  });

  const server = new McpServer(
    { name: config.mcpServerName, version: config.mcpServerVersion },
    {
      capabilities: {
        logging: {},
        resources: { listChanged: true },
        tools: {
          listChanged: true,
          requestContext: true,
          rateLimit: {
            windowMs: config.security.rateLimitWindowMs || 60 * 1000,
            maxRequests: config.security.rateLimitMaxRequests || 100,
          },
          permissions: {
            required: config.security.authRequired,
          },
        },
      },
    },
  );

  try {
    logger.debug("Registering ATLAS resources and tools...", context);
    // Register Atlas resources
    await registerMcpResources(server);

    // Register Atlas tools
    await registerAtlasProjectCreateTool(server);
    await registerAtlasProjectListTool(server);
    await registerAtlasProjectUpdateTool(server);
    await registerAtlasProjectDeleteTool(server);
    await registerAtlasTaskCreateTool(server);
    await registerAtlasTaskDeleteTool(server);
    await registerAtlasTaskListTool(server);
    await registerAtlasTaskUpdateTool(server);
    await registerAtlasDatabaseCleanTool(server);
    await registerAtlasKnowledgeAddTool(server);
    await registerAtlasKnowledgeDeleteTool(server);
    await registerAtlasKnowledgeListTool(server);
    await registerAtlasUnifiedSearchTool(server);
    await registerAtlasDeepResearchTool(server);

    logger.info("ATLAS Resources and tools registered successfully", context);
  } catch (err) {
    logger.error("Failed to register ATLAS resources/tools", {
      ...context,
      error: err instanceof Error ? err.message : String(err),
      stack: err instanceof Error ? err.stack : undefined,
    });
    throw err;
  }

  return server;
}

/**
 * Selects, sets up, and starts the appropriate MCP transport layer based on configuration.
 */
async function startTransport(): Promise<McpServer | http.Server | void> {
  const transportType = config.mcpTransportType;
  const parentContext = requestContextService.createRequestContext({
    operation: "startTransport",
    transport: transportType,
  });
  logger.info(
    `Starting transport for ATLAS MCP Server: ${transportType}`,
    parentContext,
  );

  if (transportType === "http") {
    logger.debug(
      "Delegating to startHttpTransport for ATLAS MCP Server...",
      parentContext,
    );
    const httpServerInstance = await startHttpTransport(createMcpServerInstance, parentContext);
    return httpServerInstance;
  }

  if (transportType === "stdio") {
    logger.debug(
      "Creating single McpServer instance for stdio transport (ATLAS MCP Server)...",
      parentContext,
    );
    const server = await createMcpServerInstance();
    logger.debug(
      "Delegating to connectStdioTransport for ATLAS MCP Server...",
      parentContext,
    );
    await connectStdioTransport(server, parentContext);
    return server;
  }

  logger.fatal(
    `Unsupported transport type configured for ATLAS MCP Server: ${transportType}`,
    parentContext,
  );
  throw new Error(
    `Unsupported transport type: ${transportType}. Must be 'stdio' or 'http'.`,
  );
}

/**
 * Main application entry point. Initializes and starts the MCP server.
 */
export async function initializeAndStartServer(): Promise<void | McpServer | http.Server> {
  const context = requestContextService.createRequestContext({
    operation: "initializeAndStartServer",
  });
  logger.info("ATLAS MCP Server initialization sequence started.", context);
  try {
    const result = await startTransport();
    logger.info(
      "ATLAS MCP Server initialization sequence completed successfully.",
      context,
    );
    return result;
  } catch (err) {
    logger.fatal("Critical error during ATLAS MCP server initialization.", {
      ...context,
      error: err instanceof Error ? err.message : String(err),
      stack: err instanceof Error ? err.stack : undefined,
    });
    ErrorHandler.handleError(err, {
      operation: "initializeAndStartServer", // More specific operation
      context: context, // Pass the existing context
      critical: true, // This is a critical failure
    });
    logger.info(
      "Exiting process due to critical initialization error (ATLAS MCP Server).",
      context,
    );
    process.exit(1);
  }
}

```

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

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { ProjectStatus, createProjectStatusEnum } from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasCreateProject } from "./createProject.js";
import { AtlasProjectCreateSchemaShape } from "./types.js";

export const registerAtlasProjectCreateTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_project_create",
    "Creates and initializes new projects within Atlas task management with comprehensive metadata, dependencies, and integration with the knowledge management system",
    AtlasProjectCreateSchemaShape,
    atlasCreateProject,
    createToolMetadata({
      examples: [
        createToolExample(
          {
            mode: "single",
            name: "Microservice Architecture Migration",
            description:
              "Refactor monolithic application into scalable microservices architecture with distributed data stores and API gateway",
            status: "active",
            urls: [
              {
                title: "MCP Server Repository",
                url: "https://github.com/cyanheads/atlas-mcp-server.git",
              },
              {
                title: "Technical Spec",
                url: "file:///Users/username/project_name/docs/atlas-reference.md",
              },
            ],
            completionRequirements:
              "All critical services migrated with 100% test coverage, performance metrics meeting SLAs, and zero regressions in core functionality",
            outputFormat:
              "Containerized services with CI/CD pipelines, comprehensive API documentation, and migration runbook",
            taskType: "integration",
          },
          `{
            "id": "proj_ms_migration",
            "name": "Microservice Architecture Migration",
            "description": "Refactor monolithic application into scalable microservices architecture with distributed data stores and API gateway",
            "status": "active",
            "urls": [{"title": "MCP Server Repository", "url": "https://github.com/cyanheads/atlas-mcp-server.git"}, {"title": "Technical Spec", "url": "file:///Users/username/project_name/docs/atlas-reference.md"}],
            "completionRequirements": "All critical services migrated with 100% test coverage, performance metrics meeting SLAs, and zero regressions in core functionality",
            "outputFormat": "Containerized services with CI/CD pipelines, comprehensive API documentation, and migration runbook",
            "taskType": "integration",
            "createdAt": "2025-03-23T10:11:24.123Z",
            "updatedAt": "2025-03-23T10:11:24.123Z"
          }`,
          "Initialize a high-complexity engineering project with detailed technical specifications and success criteria",
        ),
        createToolExample(
          {
            mode: "bulk",
            projects: [
              {
                name: "GraphQL API Implementation",
                description:
                  "Design and implement GraphQL API layer to replace existing REST endpoints with optimized query capabilities",
                completionRequirements:
                  "API supports all current use cases with n+1 query optimization, proper error handling, and 95% test coverage",
                outputFormat:
                  "TypeScript-based GraphQL schema with resolvers, documentation, and integration tests",
                taskType: "generation",
              },
              {
                name: "Performance Optimization Suite",
                description:
                  "Identify and resolve frontend rendering bottlenecks in React application through profiling and optimization techniques",
                status: "pending",
                completionRequirements:
                  "Core React components meet Web Vitals thresholds with 50% reduction in LCP and TTI metrics",
                outputFormat:
                  "Optimized component library, performance test suite, and technical recommendation document",
                taskType: "analysis",
              },
            ],
          },
          `{
            "success": true,
            "message": "Successfully created 2 projects",
            "created": [
              {
                "id": "proj_graphql",
                "name": "GraphQL API Implementation",
                "description": "Design and implement GraphQL API layer to replace existing REST endpoints with optimized query capabilities",
                "status": "active",
                "urls": [],
                "completionRequirements": "API supports all current use cases with n+1 query optimization, proper error handling, and 95% test coverage",
                "outputFormat": "TypeScript-based GraphQL schema with resolvers, documentation, and integration tests",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.123Z",
                "updatedAt": "2025-03-23T10:11:24.123Z"
              },
              {
                "id": "proj_perf",
                "name": "Performance Optimization Suite",
                "description": "Identify and resolve frontend rendering bottlenecks in React application through profiling and optimization techniques",
                "status": "pending",
                "urls": [],
                "completionRequirements": "Core React components meet Web Vitals thresholds with 50% reduction in LCP and TTI metrics",
                "outputFormat": "Optimized component library, performance test suite, and technical recommendation document",
                "taskType": "analysis",
                "createdAt": "2025-03-23T10:11:24.456Z",
                "updatedAt": "2025-03-23T10:11:24.456Z"
              }
            ],
            "errors": []
          }`,
          "Batch-initialize multiple specialized engineering projects with distinct technical requirements",
        ),
      ],
      requiredPermission: "project:create",
      returnSchema: z.union([
        // Single project response
        z.object({
          id: z.string().describe("Project ID"),
          name: z.string().describe("Project name"),
          description: z.string().describe("Project description"),
          status: createProjectStatusEnum().describe("Project status"),
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .describe("Reference materials"),
          completionRequirements: z.string().describe("Completion criteria"),
          outputFormat: z.string().describe("Deliverable format"),
          taskType: z.string().describe("Project classification"),
          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("Project ID"),
                name: z.string().describe("Project name"),
                description: z.string().describe("Project description"),
                status: createProjectStatusEnum().describe("Project status"),
                urls: z
                  .array(
                    z.object({
                      title: z.string(),
                      url: z.string(),
                    }),
                  )
                  .describe("Reference materials"),
                completionRequirements: z
                  .string()
                  .describe("Completion criteria"),
                outputFormat: z.string().describe("Deliverable format"),
                taskType: z.string().describe("Project classification"),
                createdAt: z.string().describe("Creation timestamp"),
                updatedAt: z.string().describe("Last update timestamp"),
              }),
            )
            .describe("Created projects"),
          errors: z
            .array(
              z.object({
                index: z.number().describe("Index in the projects array"),
                project: z.any().describe("Original project 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: 10, // 10 requests per minute (either single or bulk)
      },
    }),
  );
};

```

--------------------------------------------------------------------------------
/src/webui/logic/api-service.js:
--------------------------------------------------------------------------------

```javascript
/**
 * @fileoverview Manages all interactions with the Neo4j backend.
 * @module src/webui/logic/api-service
 */

import { config } from "./config.js";
import { dom } from "./dom-elements.js"; // Though not directly used, good for consistency if needed later
import { state, utils } from "./app-state.js";
import { uiHelpers } from "./ui-service.js";
import { renderHelpers } from "./ui-service.js"; // For rendering after fetching

/**
 * Neo4j API interaction service.
 * @type {object}
 */
export const api = {
  /**
   * Connects to the Neo4j database and verifies connectivity.
   * Initializes `state.driver`.
   * @returns {Promise<boolean>} True if connection is successful, false otherwise.
   */
  connect: async () => {
    uiHelpers.clearError();
    uiHelpers.updateNeo4jStatus("Connecting...", "var(--warning-color)");
    try {
      if (typeof neo4j === "undefined") {
        throw new Error(
          "Neo4j driver not loaded. Check CDN link in index.html.",
        );
      }
      state.driver = neo4j.driver(
        config.NEO4J_URI,
        neo4j.auth.basic(config.NEO4J_USER, config.NEO4J_PASSWORD),
      );
      await state.driver.verifyConnectivity();
      uiHelpers.updateNeo4jStatus("Connected", "var(--success-color)");
      console.log("Successfully connected to Neo4j.");
      return true;
    } catch (error) {
      console.error("Neo4j Connection Error:", error);
      uiHelpers.showError(
        `Neo4j Connection Error: ${error.message}. Check console and credentials.`,
        true,
      );
      if (dom.projectSelect) {
        dom.projectSelect.innerHTML =
          '<option value="">Neo4j Connection Error</option>';
      }
      return false;
    }
  },

  /**
   * Runs a Cypher query against the Neo4j database.
   * @param {string} query - The Cypher query to execute.
   * @param {object} [params={}] - Parameters for the query.
   * @returns {Promise<Array<object>>} A promise that resolves to an array of records.
   * @throws {Error} If not connected to Neo4j or if query fails.
   */
  runQuery: async (query, params = {}) => {
    if (!state.driver) {
      uiHelpers.showError("Not connected to Neo4j.", true);
      throw new Error("Not connected to Neo4j.");
    }
    const session = state.driver.session();
    try {
      const result = await session.run(query, params);
      return result.records.map((record) => {
        const obj = {};
        record.keys.forEach((key) => {
          const value = record.get(key);
          if (neo4j.isInt(value)) {
            obj[key] = value.toNumber();
          } else if (value && typeof value === "object" && value.properties) {
            // Node
            const nodeProps = {};
            Object.keys(value.properties).forEach((propKey) => {
              const propValue = value.properties[propKey];
              nodeProps[propKey] = neo4j.isInt(propValue)
                ? propValue.toNumber()
                : propValue;
            });
            obj[key] = nodeProps;
          } else if (
            Array.isArray(value) &&
            value.every(
              (item) => item && typeof item === "object" && item.properties,
            )
          ) {
            // Array of Nodes
            obj[key] = value.map((item) => {
              const nodeProps = {};
              Object.keys(item.properties).forEach((propKey) => {
                const propValue = item.properties[propKey];
                nodeProps[propKey] = neo4j.isInt(propValue)
                  ? propValue.toNumber()
                  : propValue;
              });
              return nodeProps;
            });
          } else {
            obj[key] = value;
          }
        });
        return obj;
      });
    } finally {
      await session.close();
    }
  },

  /**
   * Fetches all projects and populates the project selection dropdown.
   */
  fetchProjects: async () => {
    if (dom.projectSelect)
      uiHelpers.showLoading(dom.projectSelect, "Loading projects...");
    uiHelpers.setDisplay(dom.projectDetailsContainer, false);
    uiHelpers.setDisplay(dom.tasksContainer, false);
    uiHelpers.setDisplay(dom.knowledgeContainer, false);
    uiHelpers.clearError();

    if (!state.driver) {
      const connected = await api.connect();
      if (!connected) return;
    }

    try {
      const projectsData = await api.runQuery(
        "MATCH (p:Project) RETURN p.id as id, p.name as name ORDER BY p.name",
      );
      if (dom.projectSelect) {
        dom.projectSelect.innerHTML =
          '<option value="">-- Select a Project --</option>';
        let autoSelectedProjectId = null;
        if (projectsData && projectsData.length > 0) {
          projectsData.forEach((project) => {
            const option = document.createElement("option");
            option.value = project.id;
            option.textContent = utils.escapeHtml(project.name);
            dom.projectSelect.appendChild(option);
          });

          const lastSelectedProjectId = localStorage.getItem(
            "lastSelectedProjectId",
          );
          const projectIds = projectsData.map((p) => p.id);

          if (
            lastSelectedProjectId &&
            projectIds.includes(lastSelectedProjectId)
          ) {
            dom.projectSelect.value = lastSelectedProjectId;
            autoSelectedProjectId = lastSelectedProjectId;
          } else if (projectIds.length > 0) {
            dom.projectSelect.value = projectIds[0];
            autoSelectedProjectId = projectIds[0];
          }
        } else {
          dom.projectSelect.innerHTML =
            '<option value="">No projects found</option>';
        }

        if (autoSelectedProjectId) {
          // Automatically fetch details for the selected project
          api.fetchProjectDetails(autoSelectedProjectId);
        }
      }
    } catch (error) {
      console.error("Failed to fetch projects:", error);
      if (dom.projectSelect) {
        dom.projectSelect.innerHTML =
          '<option value="">Error loading projects</option>';
      }
      uiHelpers.showError(`Error loading projects: ${error.message}`);
    }
  },

  /**
   * Fetches details for a specific project, including its tasks and knowledge items.
   * Updates the application state and renders the fetched data.
   * @param {string} projectId - The ID of the project to fetch.
   */
  fetchProjectDetails: async (projectId) => {
    state.currentProjectId = projectId;
    if (!projectId) {
      uiHelpers.setDisplay(dom.projectDetailsContainer, false);
      uiHelpers.setDisplay(dom.tasksContainer, false);
      uiHelpers.setDisplay(dom.knowledgeContainer, false);
      return;
    }

    if (dom.detailsContent)
      uiHelpers.showLoading(dom.detailsContent, "Loading project details...");
    if (dom.tasksContent)
      uiHelpers.showLoading(dom.tasksContent, "Loading tasks...");
    if (dom.knowledgeContent)
      uiHelpers.showLoading(dom.knowledgeContent, "Loading knowledge items...");
    uiHelpers.setDisplay(dom.projectDetailsContainer, true);
    uiHelpers.setDisplay(dom.tasksContainer, true);
    uiHelpers.setDisplay(dom.knowledgeContainer, true);

    state.showingTaskFlow = false;
    uiHelpers.setDisplay(dom.taskFlowContainer, false);
    uiHelpers.updateToggleButton(
      dom.taskFlowToggle,
      false,
      "View Task List",
      "View Task Flow",
    );
    uiHelpers.clearError();

    try {
      const projectResult = await api.runQuery(
        "MATCH (p:Project {id: $projectId}) RETURN p",
        { projectId },
      );
      state.currentProject =
        projectResult.length > 0 ? projectResult[0].p : null;
      if (dom.detailsContent)
        renderHelpers.projectDetails(state.currentProject, dom.detailsContent);

      const tasksQuery = `
                  MATCH (proj:Project {id: $projectId})-[:CONTAINS_TASK]->(task:Task)
                  OPTIONAL MATCH (task)-[:DEPENDS_ON]->(dependency:Task)
                  RETURN task, collect(dependency.id) as dependencyIds
                  ORDER BY task.title
              `;
      const tasksResult = await api.runQuery(tasksQuery, {
        projectId,
      });
      state.currentTasks = tasksResult.map((r) => ({
        ...r.task,
        dependencyIds: r.dependencyIds || [],
      }));
      if (dom.tasksContent)
        renderHelpers.tasks(
          state.currentTasks,
          dom.tasksContent,
          state.tasksViewMode,
        );

      const knowledgeResult = await api.runQuery(
        "MATCH (p:Project {id: $projectId})-[:CONTAINS_KNOWLEDGE]->(k:Knowledge) RETURN k ORDER BY k.createdAt DESC",
        { projectId },
      );
      state.currentKnowledgeItems = knowledgeResult.map((r) => r.k);
      if (dom.knowledgeContent)
        renderHelpers.knowledgeItems(
          state.currentKnowledgeItems,
          dom.knowledgeContent,
          state.knowledgeViewMode,
        );
    } catch (error) {
      console.error(`Failed to fetch details for project ${projectId}:`, error);
      uiHelpers.showError(`Error loading project data: ${error.message}`);
      if (dom.detailsContent)
        dom.detailsContent.innerHTML = `<p class="error">Error loading project details.</p>`;
      if (dom.tasksContent)
        dom.tasksContent.innerHTML = `<p class="error">Error loading tasks.</p>`;
      if (dom.knowledgeContent)
        dom.knowledgeContent.innerHTML = `<p class="error">Error loading knowledge items.</p>`;
    }
  },
};

```

--------------------------------------------------------------------------------
/src/services/neo4j/driver.ts:
--------------------------------------------------------------------------------

```typescript
import neo4j, { Driver, ManagedTransaction, Session } from "neo4j-driver";
import { config } from "../../config/index.js";
import { logger, requestContextService } from "../../utils/index.js"; // Updated import path
import { exportDatabase } from "./index.js"; // Import the export function for backup trigger
import { databaseEvents, DatabaseEventType } from "./events.js";

/**
 * Neo4j connection management singleton
 * Responsible for creating and managing the Neo4j driver connection
 */
class Neo4jDriver {
  private static instance: Neo4jDriver;
  private driver: Driver | null = null;
  private connectionPromise: Promise<Driver> | null = null;
  private transactionCounter: number = 0;

  private constructor() {}

  /**
   * Get the Neo4jDriver singleton instance
   */
  public static getInstance(): Neo4jDriver {
    if (!Neo4jDriver.instance) {
      Neo4jDriver.instance = new Neo4jDriver();
    }
    return Neo4jDriver.instance;
  }

  /**
   * Initialize the Neo4j driver connection
   * @returns Promise that resolves to the Neo4j driver
   */
  private async initDriver(): Promise<Driver> {
    if (this.driver) {
      return this.driver;
    }

    try {
      const { neo4jUri, neo4jUser, neo4jPassword } = config;

      if (!neo4jUri || !neo4jUser || !neo4jPassword) {
        throw new Error("Neo4j connection details are not properly configured");
      }
      const reqContext = requestContextService.createRequestContext({
        operation: "Neo4jDriver.initDriver",
      });

      logger.info("Initializing Neo4j driver connection", reqContext);

      this.driver = neo4j.driver(
        neo4jUri,
        neo4j.auth.basic(neo4jUser, neo4jPassword),
        {
          maxConnectionLifetime: 3 * 60 * 60 * 1000, // 3 hours
          maxConnectionPoolSize: 50,
          connectionAcquisitionTimeout: 2 * 60 * 1000, // 2 minutes
          disableLosslessIntegers: true, // Recommended for JS compatibility
        },
      );

      // Verify connection
      await this.driver.verifyConnectivity();

      logger.info(
        "Neo4j driver connection established successfully",
        reqContext,
      );
      return this.driver;
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      // reqContext might not be defined if error occurs before its creation, so create one if needed
      const errorContext = requestContextService.createRequestContext({
        operation: "Neo4jDriver.initDriver.error",
      });
      logger.error("Failed to initialize Neo4j driver", error as Error, {
        ...errorContext,
        detail: errorMessage,
      });
      throw new Error(`Failed to initialize Neo4j connection: ${errorMessage}`);
    }
  }

  /**
   * Get the Neo4j driver instance, initializing it if necessary
   * @returns Promise that resolves to the Neo4j driver
   */
  public async getDriver(): Promise<Driver> {
    if (!this.connectionPromise) {
      this.connectionPromise = this.initDriver();
    }
    return this.connectionPromise;
  }

  /**
   * Create a new Neo4j session
   * @param database Optional database name
   * @returns Promise that resolves to a new Neo4j session
   */
  public async getSession(database?: string): Promise<Session> {
    const driver = await this.getDriver();
    // Use the default database configured for the driver instance
    // Neo4j Community Edition typically uses 'neo4j' or potentially 'system'
    // Passing undefined lets the driver use its default.
    return driver.session({
      database: database || undefined,
      defaultAccessMode: neo4j.session.WRITE,
    });
  }

  /**
   * Execute a query with a transaction
   * @param cypher Cypher query to execute
   * @param params Parameters for the query
   * @param database Optional database name
   * @returns Promise that resolves to the query result records
   */
  public async executeQuery<T = any>(
    cypher: string,
    params: Record<string, any> = {},
    database?: string,
  ): Promise<T[]> {
    const session = await this.getSession(database);

    try {
      const result = await session.executeWrite(
        async (tx: ManagedTransaction) => {
          const queryResult = await tx.run(cypher, params);
          return queryResult.records;
        },
      );

      // Publish write operation event
      // Publish write operation event
      this.publishWriteOperation({ query: cypher, params });

      // Removed: Trigger background backup after successful write
      // this.triggerBackgroundBackup(); // This was inefficient

      return result as unknown as T[];
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      const errorContext = requestContextService.createRequestContext({
        operation: "Neo4jDriver.executeQuery",
        query: cypher,
        // params: params // Consider sanitizing or summarizing params
      });
      logger.error("Error executing Neo4j query", error as Error, {
        ...errorContext,
        detail: errorMessage,
      });

      // Publish error event
      databaseEvents.publish(DatabaseEventType.ERROR, {
        timestamp: new Date().toISOString(),
        operation: "executeQuery",
        error: errorMessage,
        query: cypher,
      });

      throw error; // Re-throw the original error
    } finally {
      await session.close();
    }
  }

  /**
   * Execute a read-only query
   * @param cypher Cypher query to execute
   * @param params Parameters for the query
   * @param database Optional database name
   * @returns Promise that resolves to the query result records
   */
  public async executeReadQuery<T = any>(
    cypher: string,
    params: Record<string, any> = {},
    database?: string,
  ): Promise<T[]> {
    const session = await this.getSession(database);

    try {
      const result = await session.executeRead(
        async (tx: ManagedTransaction) => {
          const queryResult = await tx.run(cypher, params);
          return queryResult.records;
        },
      );

      // Publish read operation event
      databaseEvents.publish(DatabaseEventType.READ_OPERATION, {
        timestamp: new Date().toISOString(),
        query: cypher,
      });

      return result as unknown as T[];
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      const errorContext = requestContextService.createRequestContext({
        operation: "Neo4jDriver.executeReadQuery",
        query: cypher,
        // params: params // Consider sanitizing or summarizing params
      });
      logger.error("Error executing Neo4j read query", error as Error, {
        ...errorContext,
        detail: errorMessage,
      });

      // Publish error event
      databaseEvents.publish(DatabaseEventType.ERROR, {
        timestamp: new Date().toISOString(),
        operation: "executeReadQuery",
        error: errorMessage,
        query: cypher,
      });

      throw error; // Re-throw the original error
    } finally {
      await session.close();
    }
  }

  /**
   * Publish a database write operation event
   * @param operation Details about the operation
   * @private
   */
  private publishWriteOperation(operation: {
    query: string;
    params?: Record<string, any>;
  }): void {
    this.transactionCounter++;
    databaseEvents.publish(DatabaseEventType.WRITE_OPERATION, {
      timestamp: new Date().toISOString(),
      transactionId: this.transactionCounter,
      operation,
    });
  }

  /**
   * Triggers a database backup in the background, including rotation logic.
   * Logs errors but does not throw to avoid interrupting the main flow.
   * @private
   */
  private triggerBackgroundBackup(): void {
    const reqContext = requestContextService.createRequestContext({
      operation: "Neo4jDriver.triggerBackgroundBackup",
    });
    logger.debug(
      "Triggering background database backup with rotation...",
      reqContext,
    );
    // Run backup in the background without awaiting it
    exportDatabase()
      .then((backupPath) => {
        logger.info(`Background database backup successful: ${backupPath}`, {
          ...reqContext,
          backupPath,
        });
      })
      .catch((error) => {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
        logger.error("Background database backup failed:", error as Error, {
          ...reqContext,
          detail: errorMessage,
        });
        // Consider adding more robust error handling/notification if needed
      });
  }

  /**
   * Close the Neo4j driver connection
   */
  public async close(): Promise<void> {
    const reqContext = requestContextService.createRequestContext({
      operation: "Neo4jDriver.close",
    });
    if (this.driver) {
      try {
        await this.driver.close();
        this.driver = null;
        this.connectionPromise = null;
        logger.info("Neo4j driver connection closed", reqContext);
      } catch (error) {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
        logger.error("Error closing Neo4j driver connection", error as Error, {
          ...reqContext,
          detail: errorMessage,
        });
        throw error; // Re-throw the error to propagate it
      }
    }
  }
}

// Export the singleton instance
export const neo4jDriver = Neo4jDriver.getInstance();

```

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

```typescript
/**
 * @fileoverview Provides a utility class `IdGenerator` for creating customizable, prefixed unique identifiers,
 * and a standalone `generateUUID` function for generating standard UUIDs.
 * The `IdGenerator` supports entity-specific prefixes, custom character sets, and lengths.
 *
 * Note: Logging has been removed from this module to prevent circular dependencies
 * with the `requestContextService`, which itself uses `generateUUID` from this module.
 * This was causing `ReferenceError: Cannot access 'generateUUID' before initialization`
 * during application startup.
 * @module src/utils/security/idGenerator
 */
import { randomUUID as cryptoRandomUUID, randomBytes } from "crypto";
import { BaseErrorCode, McpError } from "../../types/errors.js";
// Removed: import { logger, requestContextService } from "../index.js";

/**
 * Defines the structure for configuring entity prefixes.
 * Keys are entity type names (e.g., "project", "task"), and values are their corresponding ID prefixes (e.g., "PROJ", "TASK").
 */
export interface EntityPrefixConfig {
  [key: string]: string;
}

/**
 * Defines options for customizing ID generation.
 */
export interface IdGenerationOptions {
  length?: number;
  separator?: string;
  charset?: string;
}

/**
 * A generic ID Generator class for creating and managing unique, prefixed identifiers.
 * Allows defining custom prefixes, generating random strings, and validating/normalizing IDs.
 */
export class IdGenerator {
  /**
   * Default character set for the random part of the ID.
   * @private
   */
  private static DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  /**
   * Default separator character between prefix and random part.
   * @private
   */
  private static DEFAULT_SEPARATOR = "_";
  /**
   * Default length for the random part of the ID.
   * @private
   */
  private static DEFAULT_LENGTH = 6;

  /**
   * Stores the mapping of entity types to their prefixes.
   * @private
   */
  private entityPrefixes: EntityPrefixConfig = {};
  /**
   * Stores a reverse mapping from prefixes (case-insensitive) to entity types.
   * @private
   */
  private prefixToEntityType: Record<string, string> = {};

  /**
   * Constructs an `IdGenerator` instance.
   * @param entityPrefixes - An initial map of entity types to their prefixes.
   */
  constructor(entityPrefixes: EntityPrefixConfig = {}) {
    // Logging removed to prevent circular dependency with requestContextService.
    this.setEntityPrefixes(entityPrefixes);
  }

  /**
   * Sets or updates the entity prefix configuration and rebuilds the internal reverse lookup map.
   * @param entityPrefixes - A map where keys are entity type names and values are their desired ID prefixes.
   */
  public setEntityPrefixes(entityPrefixes: EntityPrefixConfig): void {
    // Logging removed.
    this.entityPrefixes = { ...entityPrefixes };

    this.prefixToEntityType = Object.entries(this.entityPrefixes).reduce(
      (acc, [type, prefix]) => {
        acc[prefix.toLowerCase()] = type; // Store lowercase for case-insensitive lookup
        return acc;
      },
      {} as Record<string, string>,
    );
  }

  /**
   * Retrieves a copy of the current entity prefix configuration.
   * @returns The current entity prefix configuration.
   */
  public getEntityPrefixes(): EntityPrefixConfig {
    return { ...this.entityPrefixes };
  }

  /**
   * Generates a cryptographically secure random string.
   * @param length - The desired length of the random string. Defaults to `IdGenerator.DEFAULT_LENGTH`.
   * @param charset - The character set to use. Defaults to `IdGenerator.DEFAULT_CHARSET`.
   * @returns The generated random string.
   */
  public generateRandomString(
    length: number = IdGenerator.DEFAULT_LENGTH,
    charset: string = IdGenerator.DEFAULT_CHARSET,
  ): string {
    const bytes = randomBytes(length);
    let result = "";
    for (let i = 0; i < length; i++) {
      result += charset[bytes[i] % charset.length];
    }
    return result;
  }

  /**
   * Generates a unique ID, optionally prepended with a prefix.
   * @param prefix - An optional prefix for the ID.
   * @param options - Optional parameters for ID generation (length, separator, charset).
   * @returns A unique identifier string.
   */
  public generate(prefix?: string, options: IdGenerationOptions = {}): string {
    // Logging removed.
    const {
      length = IdGenerator.DEFAULT_LENGTH,
      separator = IdGenerator.DEFAULT_SEPARATOR,
      charset = IdGenerator.DEFAULT_CHARSET,
    } = options;

    const randomPart = this.generateRandomString(length, charset);
    const generatedId = prefix
      ? `${prefix}${separator}${randomPart}`
      : randomPart;
    return generatedId;
  }

  /**
   * Generates a unique ID for a specified entity type, using its configured prefix.
   * @param entityType - The type of entity (must be registered).
   * @param options - Optional parameters for ID generation.
   * @returns A unique identifier string for the entity (e.g., "PROJ_A6B3J0").
   * @throws {McpError} If the `entityType` is not registered.
   */
  public generateForEntity(
    entityType: string,
    options: IdGenerationOptions = {},
  ): string {
    const prefix = this.entityPrefixes[entityType];
    if (!prefix) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        `Unknown entity type: ${entityType}. No prefix registered.`,
      );
    }
    return this.generate(prefix, options);
  }

  /**
   * Validates if an ID conforms to the expected format for a specific entity type.
   * @param id - The ID string to validate.
   * @param entityType - The expected entity type of the ID.
   * @param options - Optional parameters used during generation for validation consistency.
   * @returns `true` if the ID is valid, `false` otherwise.
   */
  public isValid(
    id: string,
    entityType: string,
    options: IdGenerationOptions = {},
  ): boolean {
    const prefix = this.entityPrefixes[entityType];
    const {
      length = IdGenerator.DEFAULT_LENGTH,
      separator = IdGenerator.DEFAULT_SEPARATOR,
    } = options;

    if (!prefix) {
      return false;
    }
    // Assumes default charset characters (uppercase letters and digits) for regex.
    const pattern = new RegExp(
      `^${this.escapeRegex(prefix)}${this.escapeRegex(separator)}[A-Z0-9]{${length}}$`,
    );
    return pattern.test(id);
  }

  /**
   * Escapes special characters in a string for use in a regular expression.
   * @param str - The string to escape.
   * @returns The escaped string.
   * @private
   */
  private escapeRegex(str: string): string {
    return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  }

  /**
   * Strips the prefix and separator from an ID string.
   * @param id - The ID string (e.g., "PROJ_A6B3J0").
   * @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
   * @returns The ID part without the prefix, or the original ID if separator not found.
   */
  public stripPrefix(
    id: string,
    separator: string = IdGenerator.DEFAULT_SEPARATOR,
  ): string {
    const parts = id.split(separator);
    return parts.length > 1 ? parts.slice(1).join(separator) : id; // Handle separators in random part
  }

  /**
   * Determines the entity type from an ID string by its prefix (case-insensitive).
   * @param id - The ID string (e.g., "PROJ_A6B3J0").
   * @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
   * @returns The determined entity type.
   * @throws {McpError} If ID format is invalid or prefix is unknown.
   */
  public getEntityType(
    id: string,
    separator: string = IdGenerator.DEFAULT_SEPARATOR,
  ): string {
    const parts = id.split(separator);
    if (parts.length < 2 || !parts[0]) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        `Invalid ID format: ${id}. Expected format like: PREFIX${separator}RANDOMLPART`,
      );
    }

    const prefix = parts[0];
    const entityType = this.prefixToEntityType[prefix.toLowerCase()];

    if (!entityType) {
      throw new McpError(
        BaseErrorCode.VALIDATION_ERROR,
        `Unknown entity type for prefix: ${prefix}`,
      );
    }
    return entityType;
  }

  /**
   * Normalizes an entity ID to ensure the prefix matches the registered case
   * and the random part is uppercase.
   * @param id - The ID to normalize (e.g., "proj_a6b3j0").
   * @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
   * @returns The normalized ID (e.g., "PROJ_A6B3J0").
   * @throws {McpError} If the entity type cannot be determined from the ID.
   */
  public normalize(
    id: string,
    separator: string = IdGenerator.DEFAULT_SEPARATOR,
  ): string {
    const entityType = this.getEntityType(id, separator);
    const registeredPrefix = this.entityPrefixes[entityType];
    const idParts = id.split(separator);
    const randomPart = idParts.slice(1).join(separator);

    return `${registeredPrefix}${separator}${randomPart.toUpperCase()}`;
  }
}

/**
 * Default singleton instance of the `IdGenerator`.
 * Initialize with `idGenerator.setEntityPrefixes({})` to configure.
 */
export const idGenerator = new IdGenerator();

/**
 * Generates a standard Version 4 UUID (Universally Unique Identifier).
 * Uses the Node.js `crypto` module. This function is independent of the IdGenerator instance
 * to prevent circular dependencies when used by other utilities like requestContextService.
 * @returns A new UUID string.
 */
export const generateUUID = (): string => {
  return cryptoRandomUUID();
};

```

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

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { PriorityLevel, TaskStatus } from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasUpdateTask } from "./updateTask.js";
import { AtlasTaskUpdateSchemaShape } from "./types.js";

export const registerAtlasTaskUpdateTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_task_update",
    "Updates existing task(s) in the system with support for both individual task modifications and efficient batch updates across multiple tasks",
    AtlasTaskUpdateSchemaShape,
    atlasUpdateTask,
    createToolMetadata({
      examples: [
        createToolExample(
          {
            mode: "single",
            id: "task_api_gateway",
            updates: {
              status: "in_progress",
              description:
                "Enhanced API Gateway design with additional focus on OAuth 2.0 integration and microservice security boundaries",
              priority: "critical",
            },
          },
          `{
            "id": "task_api_gateway",
            "projectId": "proj_ms_migration",
            "title": "Design API Gateway Architecture",
            "description": "Enhanced API Gateway design with additional focus on OAuth 2.0 integration and microservice security boundaries",
            "priority": "critical",
            "status": "in_progress",
            "assignedTo": null,
            "urls": [],
            "tags": ["architecture", "api", "gateway", "security"],
            "completionRequirements": "Complete architecture diagram with data flow, scaling strategy, and disaster recovery considerations. Implementation specifications must include authentication flow and rate limiting algorithms",
            "outputFormat": "Architecture diagram (PDF), Technical specifications document (Markdown), Implementation roadmap",
            "taskType": "research",
            "createdAt": "2025-03-23T10:11:24.123Z",
            "updatedAt": "2025-03-23T10:14:51.456Z"
          }`,
          "Update task priority and add security details to an existing architecture design task",
        ),
        createToolExample(
          {
            mode: "bulk",
            tasks: [
              {
                id: "task_graphql_schema",
                updates: {
                  status: "in_progress",
                  assignedTo: "user_developer1",
                  tags: ["graphql", "schema", "foundation", "priority"],
                },
              },
              {
                id: "task_auth",
                updates: {
                  priority: "high",
                  description:
                    "Implement JWT-based authentication with refresh token rotation and resource-based authorization for GraphQL resolvers",
                },
              },
            ],
          },
          `{
            "success": true,
            "message": "Successfully updated 2 tasks",
            "updated": [
              {
                "id": "task_graphql_schema",
                "projectId": "proj_graphql",
                "title": "Set up GraphQL schema and resolver structure",
                "description": "Create the foundation for our GraphQL API by defining the base schema structure, resolver patterns, and integration with existing data sources",
                "priority": "high",
                "status": "in_progress",
                "assignedTo": "user_developer1",
                "urls": [],
                "tags": ["graphql", "schema", "foundation", "priority"],
                "completionRequirements": "Working schema structure with type definitions for core entities. Base resolver pattern implemented with at least one full query path to the database.",
                "outputFormat": "TypeScript code implementing the schema and resolvers with documentation",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.123Z",
                "updatedAt": "2025-03-23T10:14:51.456Z"
              },
              {
                "id": "task_auth",
                "projectId": "proj_graphql",
                "title": "Implement authentication and authorization",
                "description": "Implement JWT-based authentication with refresh token rotation and resource-based authorization for GraphQL resolvers",
                "priority": "high",
                "status": "backlog",
                "assignedTo": null,
                "urls": [],
                "tags": ["auth", "security", "graphql"],
                "completionRequirements": "Authentication middleware and directive implemented. All resolvers protected with appropriate permission checks.",
                "outputFormat": "TypeScript code with tests demonstrating security controls",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.456Z",
                "updatedAt": "2025-03-23T10:14:51.789Z"
              }
            ],
            "errors": []
          }`,
          "Assign a task to a developer and update the priority of a related dependency task",
        ),
      ],
      requiredPermission: "task:update",
      returnSchema: z.union([
        // Single task response
        z.object({
          id: z.string().describe("Task ID"),
          projectId: z.string().describe("Parent project ID"),
          title: z.string().describe("Task title"),
          description: z.string().describe("Task description"),
          priority: z
            .enum([
              PriorityLevel.LOW,
              PriorityLevel.MEDIUM,
              PriorityLevel.HIGH,
              PriorityLevel.CRITICAL,
            ])
            .describe("Importance level"),
          status: z
            .enum([
              TaskStatus.BACKLOG,
              TaskStatus.TODO,
              TaskStatus.IN_PROGRESS,
              TaskStatus.COMPLETED,
            ])
            .describe("Task status"),
          assignedTo: z
            .string()
            .nullable()
            .describe("ID of entity responsible for completion"),
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .describe("Reference materials"),
          tags: z.array(z.string()).describe("Organizational labels"),
          completionRequirements: z.string().describe("Completion criteria"),
          outputFormat: z.string().describe("Deliverable format"),
          taskType: z.string().describe("Task classification"),
          createdAt: z.string().describe("Creation timestamp"),
          updatedAt: z.string().describe("Last update timestamp"),
        }),
        // Bulk update response
        z.object({
          success: z.boolean().describe("Operation success status"),
          message: z.string().describe("Result message"),
          updated: z
            .array(
              z.object({
                id: z.string().describe("Task ID"),
                projectId: z.string().describe("Parent project ID"),
                title: z.string().describe("Task title"),
                description: z.string().describe("Task description"),
                priority: z
                  .enum([
                    PriorityLevel.LOW,
                    PriorityLevel.MEDIUM,
                    PriorityLevel.HIGH,
                    PriorityLevel.CRITICAL,
                  ])
                  .describe("Importance level"),
                status: z
                  .enum([
                    TaskStatus.BACKLOG,
                    TaskStatus.TODO,
                    TaskStatus.IN_PROGRESS,
                    TaskStatus.COMPLETED,
                  ])
                  .describe("Task status"),
                assignedTo: z
                  .string()
                  .nullable()
                  .describe("ID of entity responsible for completion"),
                urls: z
                  .array(
                    z.object({
                      title: z.string(),
                      url: z.string(),
                    }),
                  )
                  .describe("Reference materials"),
                tags: z.array(z.string()).describe("Organizational labels"),
                completionRequirements: z
                  .string()
                  .describe("Completion criteria"),
                outputFormat: z.string().describe("Deliverable format"),
                taskType: z.string().describe("Task classification"),
                createdAt: z.string().describe("Creation timestamp"),
                updatedAt: z.string().describe("Last update timestamp"),
              }),
            )
            .describe("Updated tasks"),
          errors: z
            .array(
              z.object({
                index: z.number().describe("Index in the tasks array"),
                task: z.any().describe("Original task update 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("Update errors"),
        }),
      ]),
      rateLimit: {
        windowMs: 60 * 1000, // 1 minute
        maxRequests: 15, // 15 requests per minute (either single or bulk)
      },
    }),
  );
};

```

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

```typescript
import { TaskService } from "../../../services/neo4j/taskService.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 { AtlasTaskCreateInput, AtlasTaskCreateSchema } from "./types.js";
import { formatTaskCreateResponse } from "./responseFormat.js";

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

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

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

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

      // Process each task sequentially to maintain consistency
      for (let i = 0; i < validatedInput.tasks.length; i++) {
        const taskData = validatedInput.tasks[i];
        try {
          // Verify project exists before creating task
          const projectExists = await ProjectService.getProjectById(
            taskData.projectId,
          );
          if (!projectExists) {
            throw new McpError(
              ProjectErrorCode.PROJECT_NOT_FOUND,
              `Project with ID ${taskData.projectId} not found`,
              { projectId: taskData.projectId },
            );
          }

          const createdTask = await TaskService.createTask({
            projectId: taskData.projectId,
            title: taskData.title,
            description: taskData.description,
            priority: taskData.priority || "medium",
            status: taskData.status || "todo",
            assignedTo: taskData.assignedTo,
            urls: taskData.urls || [],
            tags: taskData.tags || [],
            completionRequirements: taskData.completionRequirements,
            outputFormat: taskData.outputFormat,
            taskType: taskData.taskType,
            id: taskData.id, // Use client-provided ID if available
          });

          results.created.push(createdTask);

          // Create dependency relationships if specified
          if (taskData.dependencies && taskData.dependencies.length > 0) {
            for (const dependencyId of taskData.dependencies) {
              try {
                await TaskService.addTaskDependency(
                  createdTask.id,
                  dependencyId,
                );
              } catch (error) {
                const depErrorContext =
                  requestContextService.createRequestContext({
                    ...reqContext,
                    originalErrorMessage:
                      error instanceof Error ? error.message : String(error),
                    originalErrorStack:
                      error instanceof Error ? error.stack : undefined,
                    taskId: createdTask.id,
                    dependencyIdAttempted: dependencyId,
                  });
                logger.warning(
                  `Failed to create dependency for task ${createdTask.id} to ${dependencyId}`,
                  depErrorContext,
                );
              }
            }
          }
        } catch (error) {
          results.success = false;
          results.errors.push({
            index: i,
            task: taskData,
            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.tasks.length} tasks with ${results.errors.length} errors`;
      }

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

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        const mappedCreatedTasks = results.created.map((t) => {
          const { assignedToUserId, ...restOfTask } = t; // t will have assignedToUserId from service
          return { ...restOfTask, assignedTo: assignedToUserId || undefined };
        });
        const responsePayload = {
          ...results,
          created: mappedCreatedTasks,
        };
        return createToolResponse(JSON.stringify(responsePayload, null, 2));
      } else {
        // Assuming formatTaskCreateResponse can handle the raw 'results' or we map similarly
        const mappedCreatedTasksForFormatting = results.created.map((t) => {
          const { assignedToUserId, ...restOfTask } = t;
          return { ...restOfTask, assignedTo: assignedToUserId || undefined };
        });
        const formattedResponsePayload = {
          ...results,
          created: mappedCreatedTasksForFormatting,
        };
        return formatTaskCreateResponse(formattedResponsePayload);
      }
    } else {
      // Process single task creation
      const {
        mode,
        id,
        projectId,
        title,
        description,
        priority,
        status,
        assignedTo,
        urls,
        tags,
        completionRequirements,
        dependencies,
        outputFormat,
        taskType,
      } = validatedInput;

      logger.info("Initializing new task", {
        ...reqContext,
        title,
        projectId,
      });

      // Verify project exists
      const projectExists = await ProjectService.getProjectById(projectId);
      if (!projectExists) {
        throw new McpError(
          ProjectErrorCode.PROJECT_NOT_FOUND,
          `Project with ID ${projectId} not found`,
          { projectId },
        );
      }

      const task = await TaskService.createTask({
        id, // Use client-provided ID if available
        projectId,
        title,
        description,
        priority: priority || "medium",
        status: status || "todo",
        assignedTo,
        urls: urls || [],
        tags: tags || [],
        completionRequirements,
        outputFormat,
        taskType,
      });

      // Create dependency relationships if specified
      if (dependencies && dependencies.length > 0) {
        for (const dependencyId of dependencies) {
          try {
            await TaskService.addTaskDependency(task.id, dependencyId);
          } catch (error) {
            const depErrorContext = requestContextService.createRequestContext({
              ...reqContext,
              originalErrorMessage:
                error instanceof Error ? error.message : String(error),
              originalErrorStack:
                error instanceof Error ? error.stack : undefined,
              taskId: task.id,
              dependencyIdAttempted: dependencyId,
            });
            logger.warning(
              `Failed to create dependency for task ${task.id} to ${dependencyId}`,
              depErrorContext,
            );
          }
        }
      }

      logger.info("Task initialized successfully", {
        ...reqContext,
        taskId: task.id,
        projectId,
      });

      // Conditionally format response
      if (validatedInput.responseFormat === ResponseFormat.JSON) {
        const { assignedToUserId, ...restOfTask } = task; // task from service has assignedToUserId
        const responsePayload = {
          ...restOfTask,
          assignedTo: assignedToUserId || undefined,
        };
        return createToolResponse(JSON.stringify(responsePayload, null, 2));
      } else {
        const { assignedToUserId, ...restOfTask } = task;
        const formattedResponsePayload = {
          ...restOfTask,
          assignedTo: assignedToUserId || undefined,
        };
        return formatTaskCreateResponse(formattedResponsePayload);
      }
    }
  } catch (error) {
    // Handle specific error cases
    if (error instanceof McpError) {
      throw error;
    }

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

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

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

```

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

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

/**
 * @fileoverview Generates a visual tree representation of the project's directory structure.
 * @module scripts/tree
 *   Respects .gitignore patterns and common exclusions (e.g., node_modules).
 *   Saves the tree to a markdown file (default: docs/tree.md).
 *   Supports custom output path and depth limitation.
 *   Ensures all file operations are within the project root for security.
 *
 * @example
 * // Generate tree with default settings:
 * // npm run tree
 *
 * @example
 * // Specify custom output path and depth:
 * // ts-node --esm scripts/tree.ts ./documentation/structure.md --depth=3
 */

import fs from "fs/promises";
import ignore from "ignore"; // Import the 'ignore' library
import path from "path";

// Get the type of the instance returned by ignore()
type Ignore = ReturnType<typeof ignore>;

const projectRoot = process.cwd();
let outputPathArg = "docs/tree.md"; // Default output path
let maxDepthArg = Infinity;

const args = process.argv.slice(2);
if (args.includes("--help")) {
  console.log(`
Generate Tree - Project directory structure visualization tool

Usage:
  ts-node --esm scripts/tree.ts [output-path] [--depth=<number>] [--help]

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

args.forEach((arg) => {
  if (arg.startsWith("--depth=")) {
    const depthValue = parseInt(arg.split("=")[1], 10);
    if (!isNaN(depthValue) && depthValue >= 0) {
      maxDepthArg = depthValue;
    } else {
      console.warn(`Invalid depth value: "${arg}". Using unlimited depth.`);
    }
  } else if (!arg.startsWith("--")) {
    outputPathArg = arg;
  }
});

const DEFAULT_IGNORE_PATTERNS: string[] = [
  ".git",
  "node_modules",
  ".DS_Store",
  "dist",
  "build",
  "logs",
];

/**
 * Loads and parses patterns from the .gitignore file at the project root,
 * and combines them with default ignore patterns.
 * @returns A promise resolving to an Ignore instance from the 'ignore' library.
 */
async function loadIgnoreHandler(): Promise<Ignore> {
  const ig = ignore();
  ig.add(DEFAULT_IGNORE_PATTERNS); // Add default patterns first

  const gitignorePath = path.join(projectRoot, ".gitignore");
  try {
    // Security: Ensure we read only from within the project root
    if (!path.resolve(gitignorePath).startsWith(projectRoot + path.sep)) {
      console.warn(
        "Warning: Attempted to read .gitignore outside project root. Using default ignore patterns only.",
      );
      return ig;
    }
    const gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
    ig.add(gitignoreContent); // Add patterns from .gitignore file
  } catch (error: any) {
    if (error.code === "ENOENT") {
      console.warn(
        "Info: No .gitignore file found at project root. Using default ignore patterns only.",
      );
    } else {
      console.error(`Error reading .gitignore: ${error.message}`);
    }
  }
  return ig;
}

/**
 * Checks if a given path should be ignored.
 * @param entryPath - The absolute path to the file or directory entry.
 * @param ig - An Ignore instance from the 'ignore' library.
 * @returns True if the path should be ignored, false otherwise.
 */
function isIgnored(entryPath: string, ig: Ignore): boolean {
  const relativePath = path.relative(projectRoot, entryPath);
  // The 'ignore' library expects POSIX-style paths (with /) even on Windows
  const posixRelativePath = relativePath.split(path.sep).join(path.posix.sep);
  return ig.ignores(posixRelativePath);
}

/**
 * Recursively generates a string representation of the directory tree.
 * @param dir - The absolute path of the directory to traverse.
 * @param ig - An Ignore instance.
 * @param prefix - String prefix for formatting the tree lines.
 * @param currentDepth - Current depth of traversal.
 * @returns A promise resolving to the tree string.
 */
async function generateTree(
  dir: string,
  ig: Ignore,
  prefix = "",
  currentDepth = 0,
): Promise<string> {
  const resolvedDir = path.resolve(dir);
  if (
    !resolvedDir.startsWith(projectRoot + path.sep) &&
    resolvedDir !== projectRoot
  ) {
    console.warn(
      `Security: Skipping directory outside project root: ${resolvedDir}`,
    );
    return "";
  }

  if (currentDepth > maxDepthArg) {
    return "";
  }

  let entries;
  try {
    entries = await fs.readdir(resolvedDir, { withFileTypes: true });
  } catch (error: any) {
    console.error(`Error reading directory ${resolvedDir}: ${error.message}`);
    return "";
  }

  let output = "";
  const filteredEntries = entries
    .filter((entry) => !isIgnored(path.join(resolvedDir, entry.name), ig))
    .sort((a, b) => {
      if (a.isDirectory() && !b.isDirectory()) return -1;
      if (!a.isDirectory() && b.isDirectory()) return 1;
      return a.name.localeCompare(b.name);
    });

  for (let i = 0; i < filteredEntries.length; i++) {
    const entry = filteredEntries[i];
    const isLastEntry = i === filteredEntries.length - 1;
    const connector = isLastEntry ? "└── " : "├── ";
    const newPrefix = prefix + (isLastEntry ? "    " : "│   ");

    output += prefix + connector + entry.name + "\n";

    if (entry.isDirectory()) {
      output += await generateTree(
        path.join(resolvedDir, entry.name),
        ig,
        newPrefix,
        currentDepth + 1,
      );
    }
  }
  return output;
}

/**
 * Main function to orchestrate loading ignore patterns, generating the tree,
 * and writing it to the specified output file.
 */
const writeTreeToFile = async (): Promise<void> => {
  try {
    const projectName = path.basename(projectRoot);
    const ignoreHandler = await loadIgnoreHandler(); // Get the Ignore instance
    const resolvedOutputFile = path.resolve(projectRoot, outputPathArg);

    // Security Validation for Output Path
    if (!resolvedOutputFile.startsWith(projectRoot + path.sep)) {
      console.error(
        `Error: Output path "${outputPathArg}" resolves outside the project directory: ${resolvedOutputFile}. Aborting.`,
      );
      process.exit(1);
    }
    const resolvedOutputDir = path.dirname(resolvedOutputFile);
    if (
      !resolvedOutputDir.startsWith(projectRoot + path.sep) &&
      resolvedOutputDir !== projectRoot
    ) {
      console.error(
        `Error: Output directory "${resolvedOutputDir}" is outside the project directory. Aborting.`,
      );
      process.exit(1);
    }

    console.log(`Generating directory tree for project: ${projectName}`);
    console.log(`Output will be saved to: ${resolvedOutputFile}`);
    if (maxDepthArg !== Infinity) {
      console.log(`Maximum depth set to: ${maxDepthArg}`);
    }

    const newGeneratedTreeContent = await generateTree(
      projectRoot,
      ignoreHandler,
      "",
      0,
    ); // Pass the Ignore instance

    let existingRawTreeContent: string | null = null;
    try {
      const currentFileContent = await fs.readFile(resolvedOutputFile, "utf-8");

      // Escape projectName for use in regex
      const escapedProjectName = projectName.replace(
        /[.*+?^${}()|[\]\\]/g,
        "\\$&",
      );

      // Regex to find the tree block:
      // Matches ``` (optional language specifier) \n
      // then projectName \n
      // then captures the content (non-greedy)
      // until it finds \n``` at the end of a line in the code block
      const treeBlockRegex = new RegExp(
        `^\\s*\`\`\`(?:[^\\n]*)\\n${escapedProjectName}\\n([\\s\\S]*?)\\n\`\`\`\\s*$`,
        "m",
      );

      const match = currentFileContent.match(treeBlockRegex);
      if (match && typeof match[1] === "string") {
        existingRawTreeContent = match[1];
      }
    } catch (error: any) {
      if (error.code !== "ENOENT") {
        // ENOENT (file not found) is expected if the file hasn't been created yet.
        console.warn(
          `Warning: Could not read existing output file ("${resolvedOutputFile}") for comparison: ${error.message}`,
        );
      }
      // If file doesn't exist or is unreadable, existingRawTreeContent remains null,
      // which will trigger a write operation.
    }

    // Normalize line endings for comparison (Git might change LF to CRLF on Windows)
    const normalize = (str: string | null) =>
      str?.replace(/\r\n/g, "\n") ?? null;

    if (
      normalize(existingRawTreeContent) === normalize(newGeneratedTreeContent)
    ) {
      console.log(
        `Directory structure is unchanged. Output file not updated: ${resolvedOutputFile}`,
      );
    } else {
      // Content has changed, or file is new/unreadable; proceed to write.
      // Ensure the output directory exists. fs.mkdir with recursive:true will create it if it doesn't exist,
      // and will not throw an error if it already exists.
      await fs.mkdir(resolvedOutputDir, { recursive: true });

      const timestamp = new Date()
        .toISOString()
        .replace(/T/, " ")
        .replace(/\..+/, "");
      const fileHeader = `# ${projectName} - Directory Structure\n\nGenerated on: ${timestamp}\n`;
      const depthInfo =
        maxDepthArg !== Infinity
          ? `\n_Depth limited to ${maxDepthArg} levels_\n\n`
          : "\n";
      // Use the newly generated tree content for the output
      const treeBlock = `\`\`\`\n${projectName}\n${newGeneratedTreeContent}\`\`\`\n`;
      const fileFooter = `\n_Note: This tree excludes files and directories matched by .gitignore and default patterns._\n`;
      const finalContent = fileHeader + depthInfo + treeBlock + fileFooter;

      await fs.writeFile(resolvedOutputFile, finalContent);
      console.log(
        `Successfully generated and updated tree structure in: ${resolvedOutputFile}`,
      );
    }
  } catch (error) {
    console.error(
      `Error generating tree: ${error instanceof Error ? error.message : String(error)}`,
    );
    process.exit(1);
  }
};

writeTreeToFile();

```

--------------------------------------------------------------------------------
/src/services/neo4j/searchService/fullTextSearchLogic.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Implements the full-text search logic for Neo4j entities.
 * @module src/services/neo4j/searchService/fullTextSearchLogic
 */

import { Session } from "neo4j-driver";
import { logger, requestContextService } from "../../../utils/index.js";
import { neo4jDriver } from "../driver.js";
import {
  NodeLabels,
  PaginatedResult,
  RelationshipTypes,
  SearchOptions,
} from "../types.js";
import { Neo4jUtils } from "../utils.js";
import { SearchResultItem } from "./searchTypes.js";

/**
 * Perform a full-text search across multiple entity types.
 * @param searchValue The string to search for.
 * @param options Search options, excluding those not relevant to full-text search.
 * @returns Paginated search results.
 */
export async function _fullTextSearch(
  searchValue: string,
  options: Omit<
    SearchOptions,
    "value" | "fuzzy" | "caseInsensitive" | "property" | "assignedToUserId"
  > = {},
): Promise<PaginatedResult<SearchResultItem>> {
  const reqContext_fullText = requestContextService.createRequestContext({
    operation: "SearchService._fullTextSearch", // Updated operation name
    searchValue,
    searchOptions: options,
  });
  try {
    const rawEntityTypes = options.entityTypes;
    const taskType = options.taskType;
    const page = options.page || 1;
    const limit = options.limit || 20;

    const defaultEntityTypesList = ["project", "task", "knowledge"];
    const typesToUse =
      rawEntityTypes &&
      Array.isArray(rawEntityTypes) &&
      rawEntityTypes.length > 0
        ? rawEntityTypes
        : defaultEntityTypesList;

    if (!searchValue || searchValue.trim() === "") {
      throw new Error("Search value cannot be empty");
    }

    const targetLabels = typesToUse.map((l) => l.toLowerCase());

    const searchResults: SearchResultItem[] = [];

    if (targetLabels.includes("project")) {
      let projectSession: Session | null = null;
      try {
        projectSession = await neo4jDriver.getSession();
        const query = `
          CALL db.index.fulltext.queryNodes("project_fulltext", $searchValue)
          YIELD node AS p, score
          ${taskType ? "WHERE p.taskType = $taskType" : ""}
          RETURN
            p.id AS id, 'project' AS type, p.taskType AS entityType,
            p.name AS title, p.description AS description,
            'full-text' AS matchedProperty,
            CASE
              WHEN score > 2 THEN p.name
              WHEN size(toString(p.description)) > 100 THEN left(toString(p.description), 100) + '...'
              ELSE toString(p.description)
            END AS matchedValue,
            p.createdAt AS createdAt, p.updatedAt AS updatedAt,
            p.id as projectId,
            p.name as projectName,
            score * 2 AS adjustedScore
        `;
        await projectSession.executeRead(async (tx) => {
          const result = await tx.run(query, {
            searchValue,
            ...(taskType && { taskType }),
          });
          const items = result.records.map((record) => {
            const data = record.toObject();
            const scoreValue = data.adjustedScore;
            const score = typeof scoreValue === "number" ? scoreValue : 5;
            return {
              ...data,
              score,
              description:
                typeof data.description === "string"
                  ? data.description
                  : undefined,
              entityType: data.entityType || undefined,
              createdAt: data.createdAt || undefined,
              updatedAt: data.updatedAt || undefined,
              projectId: data.projectId || undefined,
              projectName: data.projectName || undefined,
            } as SearchResultItem;
          });
          searchResults.push(...items);
        });
      } catch (err) {
        logger.error(
          "Error during project full-text search query",
          err as Error,
          {
            ...reqContext_fullText,
            targetLabel: "project",
            detail: (err as Error).message,
          },
        );
      } finally {
        if (projectSession) await projectSession.close();
      }
    }

    if (targetLabels.includes("task")) {
      let taskSession: Session | null = null;
      try {
        taskSession = await neo4jDriver.getSession();
        const query = `
          CALL db.index.fulltext.queryNodes("task_fulltext", $searchValue)
          YIELD node AS t, score
          ${taskType ? "WHERE t.taskType = $taskType" : ""}
          MATCH (p:${NodeLabels.Project} {id: t.projectId})
          RETURN
            t.id AS id, 'task' AS type, t.taskType AS entityType,
            t.title AS title, t.description AS description,
            'full-text' AS matchedProperty,
            CASE
              WHEN score > 2 THEN t.title
              WHEN size(toString(t.description)) > 100 THEN left(toString(t.description), 100) + '...'
              ELSE toString(t.description)
            END AS matchedValue,
            t.createdAt AS createdAt, t.updatedAt AS updatedAt,
            t.projectId AS projectId, p.name AS projectName,
            score * 1.5 AS adjustedScore
        `;
        await taskSession.executeRead(async (tx) => {
          const result = await tx.run(query, {
            searchValue,
            ...(taskType && { taskType }),
          });
          const items = result.records.map((record) => {
            const data = record.toObject();
            const scoreValue = data.adjustedScore;
            const score = typeof scoreValue === "number" ? scoreValue : 5;
            return {
              ...data,
              score,
              description:
                typeof data.description === "string"
                  ? data.description
                  : undefined,
              entityType: data.entityType || undefined,
              createdAt: data.createdAt || undefined,
              updatedAt: data.updatedAt || undefined,
              projectId: data.projectId || undefined,
              projectName: data.projectName || undefined,
            } as SearchResultItem;
          });
          searchResults.push(...items);
        });
      } catch (err) {
        logger.error("Error during task full-text search query", err as Error, {
          ...reqContext_fullText,
          targetLabel: "task",
          detail: (err as Error).message,
        });
      } finally {
        if (taskSession) await taskSession.close();
      }
    }

    if (targetLabels.includes("knowledge")) {
      let knowledgeSession: Session | null = null;
      try {
        knowledgeSession = await neo4jDriver.getSession();
        const query = `
          CALL db.index.fulltext.queryNodes("knowledge_fulltext", $searchValue)
          YIELD node AS k, score
          MATCH (p:${NodeLabels.Project} {id: k.projectId})
          OPTIONAL MATCH (k)-[:${RelationshipTypes.BELONGS_TO_DOMAIN}]->(d:${NodeLabels.Domain})
          RETURN
            k.id AS id, 'knowledge' AS type, d.name AS entityType,
            CASE
              WHEN k.text IS NULL THEN 'Untitled Knowledge'
              WHEN size(toString(k.text)) <= 50 THEN toString(k.text)
              ELSE substring(toString(k.text), 0, 50) + '...'
            END AS title,
            k.text AS description,
            'text' AS matchedProperty,
            CASE
              WHEN size(toString(k.text)) > 100 THEN left(toString(k.text), 100) + '...'
              ELSE toString(k.text)
            END AS matchedValue,
            k.createdAt AS createdAt, k.updatedAt AS updatedAt,
            k.projectId AS projectId, p.name AS projectName,
            score AS adjustedScore
        `;
        await knowledgeSession.executeRead(async (tx) => {
          const result = await tx.run(query, { searchValue });
          const items = result.records.map((record) => {
            const data = record.toObject();
            const scoreValue = data.adjustedScore;
            const score = typeof scoreValue === "number" ? scoreValue : 5;
            return {
              ...data,
              score,
              description:
                typeof data.description === "string"
                  ? data.description
                  : undefined,
              entityType: data.entityType || undefined,
              createdAt: data.createdAt || undefined,
              updatedAt: data.updatedAt || undefined,
              projectId: data.projectId || undefined,
              projectName: data.projectName || undefined,
            } as SearchResultItem;
          });
          searchResults.push(...items);
        });
      } catch (err) {
        logger.error(
          "Error during knowledge full-text search query",
          err as Error,
          {
            ...reqContext_fullText,
            targetLabel: "knowledge",
            detail: (err as Error).message,
          },
        );
      } finally {
        if (knowledgeSession) await knowledgeSession.close();
      }
    }

    searchResults.sort((a, b) => {
      if (b.score !== a.score) return b.score - a.score;
      const dateA = a.updatedAt || a.createdAt || "1970-01-01T00:00:00.000Z";
      const dateB = b.updatedAt || b.createdAt || "1970-01-01T00:00:00.000Z";
      return new Date(dateB).getTime() - new Date(dateA).getTime();
    });

    return Neo4jUtils.paginateResults(searchResults, { page, limit });
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    logger.error("Error performing full-text search", error as Error, {
      ...reqContext_fullText,
      detail: errorMessage,
    });
    if (errorMessage.includes("Unable to find index")) {
      logger.warning(
        "Full-text index might not be configured correctly or supported in this Neo4j version.",
        { ...reqContext_fullText, detail: "Index not found warning" },
      );
      throw new Error(
        `Full-text search failed: Index not found or query error. (${errorMessage})`,
      );
    }
    throw error;
  }
}

```

--------------------------------------------------------------------------------
/src/services/neo4j/helpers.ts:
--------------------------------------------------------------------------------

```typescript
import { randomUUID } from "crypto";
import neo4j from "neo4j-driver"; // Import the neo4j driver
import { NodeLabels } from "./types.js"; // Import NodeLabels
import { Neo4jUtils } from "./utils.js"; // Import Neo4jUtils

/**
 * Helper functions for the Neo4j service
 */

/**
 * Generate a unique ID string
 * @returns A unique string ID (without hyphens)
 */
export function generateId(): string {
  return randomUUID().replace(/-/g, "");
}

/**
 * Escapes a relationship type string for safe use in Cypher queries.
 * It wraps the type in backticks and escapes any existing backticks within the type string.
 * @param type The relationship type string to escape.
 * @returns The escaped relationship type string.
 */
export const escapeRelationshipType = (type: string): string => {
  // Backtick the type name and escape any backticks within the name itself.
  return `\`${type.replace(/`/g, "``")}\``;
};

/**
 * Generate a timestamped ID with an optional prefix
 * @param prefix Optional prefix for the ID
 * @returns A unique ID with timestamp and random component
 */
export function generateTimestampedId(prefix?: string): string {
  const timestamp = Date.now().toString(36);
  const random = Math.random().toString(36).substring(2, 10);
  return prefix ? `${prefix}_${timestamp}${random}` : `${timestamp}${random}`;
}

// Removed unused toNeo4jParams function

/**
 * Build a Neo4j update query dynamically based on provided fields
 * @param nodeLabel Neo4j node label
 * @param identifier Node identifier in the query (e.g., 'n')
 * @param updates Updates to apply
 * @returns Object with setClauses and params
 */
export function buildUpdateQuery(
  nodeLabel: string, // Keep nodeLabel for potential future use or context
  identifier: string,
  updates: Record<string, any>,
): { setClauses: string[]; params: Record<string, any> } {
  const params: Record<string, any> = {};
  const setClauses: string[] = [];

  // Add update timestamp automatically
  const now = new Date().toISOString();
  params.updatedAt = now;
  setClauses.push(`${identifier}.updatedAt = $updatedAt`);

  // Add update clauses for each provided field in the updates object
  for (const [key, value] of Object.entries(updates)) {
    // Ensure we don't try to overwrite the id or createdAt
    if (key !== "id" && key !== "createdAt" && value !== undefined) {
      params[key] = value;
      setClauses.push(`${identifier}.${key} = $${key}`);
    }
  }

  return { setClauses, params };
}

/**
 * Interface for filter options used in buildListQuery
 */
interface ListQueryFilterOptions {
  projectId?: string; // Always required for Task/Knowledge, handled in MATCH
  status?: string | string[];
  priority?: string | string[];
  assignedTo?: string; // Requires specific MATCH clause handling
  taskType?: string;
  tags?: string[];
  domain?: string; // Requires specific MATCH clause handling
  search?: string; // Requires specific WHERE clause handling (e.g., regex or full-text)
  // Add other potential filters here
}

/**
 * Interface for pagination and sorting options used in buildListQuery
 */
interface ListQueryPaginationOptions {
  sortBy?: string;
  sortDirection?: "asc" | "desc";
  page?: number;
  limit?: number;
}

/**
 * Interface for the result of buildListQuery
 */
interface ListQueryResult {
  countQuery: string;
  dataQuery: string;
  params: Record<string, any>;
}

/**
 * Builds dynamic Cypher queries for listing entities with filtering, sorting, and pagination.
 *
 * @param label The primary node label (e.g., NodeLabels.Task, NodeLabels.Knowledge)
 * @param returnProperties An array of properties or expressions to return for the data query (e.g., ['t.id as id', 'u.name as userName'])
 * @param filters Filter options based on ListQueryFilterOptions
 * @param pagination Pagination and sorting options based on ListQueryPaginationOptions
 * @param nodeAlias Alias for the primary node in the query (default: 'n')
 * @param additionalMatchClauses Optional string containing additional MATCH or OPTIONAL MATCH clauses (e.g., for relationships like assigned user or domain)
 * @returns ListQueryResult containing the count query, data query, and parameters
 */
export function buildListQuery(
  label: NodeLabels,
  returnProperties: string[],
  filters: ListQueryFilterOptions,
  pagination: ListQueryPaginationOptions,
  nodeAlias: string = "n",
  additionalMatchClauses: string = "",
): ListQueryResult {
  const params: Record<string, any> = {};
  let conditions: string[] = [];

  // --- Base MATCH Clause ---
  // projectId is handled directly in the MATCH for Task and Knowledge
  let projectIdFilter = "";
  // Only add projectId filter if it's provided and not the wildcard '*'
  if (filters.projectId && filters.projectId !== "*") {
    projectIdFilter = `{projectId: $projectId}`;
    params.projectId = filters.projectId;
  }
  let baseMatch = `MATCH (${nodeAlias}:${label} ${projectIdFilter})`;

  // --- Additional MATCH Clauses (Relationships) ---
  // Add user-provided MATCH/OPTIONAL MATCH clauses
  const fullMatchClause = `${baseMatch}\n${additionalMatchClauses}`;

  // --- WHERE Clause Conditions ---
  // Add assignedTo to params if it's part of the filters and used in additionalMatchClauses
  if (filters.assignedTo) {
    params.assignedTo = filters.assignedTo;
  }

  // Status filter
  if (filters.status) {
    if (Array.isArray(filters.status) && filters.status.length > 0) {
      params.statusList = filters.status;
      conditions.push(`${nodeAlias}.status IN $statusList`);
    } else if (typeof filters.status === "string") {
      params.status = filters.status;
      conditions.push(`${nodeAlias}.status = $status`);
    }
  }
  // Priority filter (assuming it applies to the primary node)
  if (filters.priority) {
    if (Array.isArray(filters.priority) && filters.priority.length > 0) {
      params.priorityList = filters.priority;
      conditions.push(`${nodeAlias}.priority IN $priorityList`);
    } else if (typeof filters.priority === "string") {
      params.priority = filters.priority;
      conditions.push(`${nodeAlias}.priority = $priority`);
    }
  }
  // TaskType filter (assuming it applies to the primary node)
  if (filters.taskType) {
    params.taskType = filters.taskType;
    conditions.push(`${nodeAlias}.taskType = $taskType`);
  }
  // Tags filter (using helper)
  if (filters.tags && filters.tags.length > 0) {
    // Ensure Neo4jUtils is accessible or import it if helpers.ts is separate
    // Assuming Neo4jUtils is available in scope or imported
    const tagQuery = Neo4jUtils.generateArrayInListQuery(
      nodeAlias,
      "tags",
      "tagsList",
      filters.tags,
    );
    if (tagQuery.cypher) {
      conditions.push(tagQuery.cypher);
      Object.assign(params, tagQuery.params);
    }
  }
  // Text search filter (Knowledge specific, using regex for now)
  if (label === NodeLabels.Knowledge && filters.search) {
    // Use case-insensitive regex
    params.search = `(?i).*${filters.search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}.*`;
    conditions.push(`${nodeAlias}.text =~ $search`);
    // TODO: Consider switching to full-text index search for performance:
    // conditions.push(`apoc.index.search('${NodeLabels.Knowledge}_fulltext', $search) YIELD node as ${nodeAlias}`);
    // This would require changing the MATCH structure significantly.
  }
  // Domain filter is handled via additionalMatchClauses typically

  const whereClause =
    conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";

  // --- Sorting ---
  const sortField = pagination.sortBy || "createdAt"; // Default sort field
  const sortDirection = pagination.sortDirection || "desc"; // Default sort direction
  const orderByClause = `ORDER BY ${nodeAlias}.${sortField} ${sortDirection.toUpperCase()}`;

  // --- Pagination ---
  const page = Math.max(pagination.page || 1, 1);
  const limit = Math.min(Math.max(pagination.limit || 20, 1), 100);
  const skip = (page - 1) * limit;
  // Use neo4j.int() to ensure skip and limit are treated as integers
  params.skip = neo4j.int(skip);
  params.limit = neo4j.int(limit);
  const paginationClause = `SKIP $skip LIMIT $limit`;

  // --- Count Query ---
  const countQuery = `
    ${fullMatchClause}
    ${whereClause}
    RETURN count(DISTINCT ${nodeAlias}) as total
  `;

  // --- Data Query ---
  // Use WITH clause to pass distinct nodes after filtering before collecting relationships
  // This is crucial if additionalMatchClauses involve OPTIONAL MATCH that could multiply rows
  const dataQuery = `
    ${fullMatchClause}
    ${whereClause}
    WITH DISTINCT ${nodeAlias} ${additionalMatchClauses ? ", " + additionalMatchClauses.split(" ")[1] : ""} // Pass distinct primary node and potentially relationship aliases
    ${orderByClause} // Order before skip/limit
    ${paginationClause}
    // Re-apply OPTIONAL MATCHes if needed after pagination to get related data for the paginated set
    ${additionalMatchClauses} // Re-apply OPTIONAL MATCH here if needed for RETURN
    RETURN ${returnProperties.join(",\n           ")}
  `;

  // Refined Data Query structure (alternative): Apply OPTIONAL MATCH *after* pagination
  // This can be more efficient if relationship data is only needed for the final page results.
  const dataQueryAlternative = `
    ${baseMatch} // Only match the primary node initially
    ${whereClause} // Apply filters on the primary node
    WITH ${nodeAlias}
    ${orderByClause}
    ${paginationClause}
    // Now apply OPTIONAL MATCHes for related data for the paginated nodes
    ${additionalMatchClauses} 
    RETURN ${returnProperties.join(",\n           ")}
  `;
  // Choosing dataQueryAlternative as it's generally more performant for pagination

  // Remove skip/limit from count params
  const countParams = { ...params };
  delete countParams.skip;
  delete countParams.limit;

  return {
    countQuery: countQuery,
    dataQuery: dataQueryAlternative, // Use the alternative query
    params: params, // Return params including skip/limit for the data query
  };
}

```

--------------------------------------------------------------------------------
/src/mcp/resources/knowledge/knowledgeResources.ts:
--------------------------------------------------------------------------------

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

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

        // Parse query parameters
        const queryParams = new URLSearchParams(uri.search);
        // Default project ID required by knowledge service
        const projectId = queryParams.get("projectId") || "*";

        const filters: KnowledgeFilterOptions = {
          projectId,
        };

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

        // Parse tags parameter
        const tags = queryParams.get("tags");
        if (tags) {
          // Split comma-separated tags
          filters.tags = String(tags)
            .split(",")
            .map((tag) => tag.trim());
        }

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

        // 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;

        // Query the database
        const result = await KnowledgeService.getKnowledge(filters);

        // Map Neo4j knowledge items to resource objects
        const knowledgeResources = result.data.map((item) =>
          toKnowledgeResource(item),
        );

        return {
          contents: [
            {
              uri: uri.href,
              mimeType: "application/json",
              text: JSON.stringify(
                {
                  knowledge: knowledgeResources,
                  pagination: {
                    total: result.total,
                    page: result.page,
                    limit: result.limit,
                    totalPages: result.totalPages,
                  },
                },
                null,
                2,
              ),
            },
          ],
        };
      } catch (error) {
        logger.error("Error listing knowledge items", 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 knowledge items: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    },
  );

  // Get knowledge by ID
  server.resource(
    "knowledge-by-id",
    ResourceTemplates.KNOWLEDGE,
    {
      name: "Knowledge by ID",
      description: "Retrieves a single knowledge item by its unique identifier",
      mimeType: "application/json",
    },
    async (uri, params) => {
      const reqContext = requestContextService.createRequestContext({
        operation: "getKnowledgeById",
        resourceUri: uri.href,
        knowledgeIdParam: params.knowledgeId,
      });
      try {
        const knowledgeId = params.knowledgeId as string;

        logger.info("Fetching knowledge by ID", {
          ...reqContext,
          knowledgeId, // Already in reqContext but can be explicit for clarity
          uri: uri.href, // Already in reqContext but can be explicit
        });

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

        // Query the database
        const knowledge = await KnowledgeService.getKnowledgeById(knowledgeId);

        if (!knowledge) {
          throw new McpError(
            BaseErrorCode.NOT_FOUND,
            `Knowledge item with ID ${knowledgeId} not found`,
            { knowledgeId },
          );
        }

        // Convert to resource object
        const knowledgeResource = toKnowledgeResource(knowledge);

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

        logger.error("Error fetching knowledge 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 knowledge: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    },
  );

  // List knowledge by project
  server.resource(
    "knowledge-by-project",
    ResourceTemplates.KNOWLEDGE_BY_PROJECT,
    {
      name: "Knowledge by Project",
      description:
        "Retrieves all knowledge items belonging to a specific project",
      mimeType: "application/json",
    },
    async (uri, params) => {
      const reqContext = requestContextService.createRequestContext({
        operation: "listKnowledgeByProject",
        resourceUri: uri.href,
        projectIdParam: params.projectId,
      });
      try {
        const projectId = params.projectId as string;

        logger.info("Listing knowledge for project", {
          ...reqContext,
          projectId, // Already in reqContext but can be explicit
          uri: uri.href, // Already in reqContext
        });

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

        // Verify the project exists
        const project = await ProjectService.getProjectById(projectId);
        if (!project) {
          throw new McpError(
            ProjectErrorCode.PROJECT_NOT_FOUND,
            `Project with ID ${projectId} not found`,
            { projectId },
          );
        }

        // Parse query parameters
        const queryParams = new URLSearchParams(uri.search);
        const filters: KnowledgeFilterOptions = {
          projectId,
        };

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

        // Parse tags parameter
        const tags = queryParams.get("tags");
        if (tags) {
          // Split comma-separated tags
          filters.tags = String(tags)
            .split(",")
            .map((tag) => tag.trim());
        }

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

        // 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;

        // Query the database
        const result = await KnowledgeService.getKnowledge(filters);

        // Map Neo4j knowledge items to resource objects
        const knowledgeResources = result.data.map((item) =>
          toKnowledgeResource(item),
        );

        return {
          contents: [
            {
              uri: uri.href,
              mimeType: "application/json",
              text: JSON.stringify(
                {
                  projectId,
                  projectName: project.name,
                  knowledge: knowledgeResources,
                  pagination: {
                    total: result.total,
                    page: result.page,
                    limit: result.limit,
                    totalPages: result.totalPages,
                  },
                },
                null,
                2,
              ),
            },
          ],
        };
      } catch (error) {
        // Handle specific error cases
        if (error instanceof McpError) {
          throw error;
        }

        logger.error("Error listing knowledge for project", 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 list knowledge for project: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    },
  );
}

```

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

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { PriorityLevel, TaskStatus } from "../../../types/mcp.js";
import {
  createToolExample,
  createToolMetadata,
  registerTool,
} from "../../../types/tool.js";
import { atlasCreateTask } from "./createTask.js";
import { AtlasTaskCreateSchemaShape } from "./types.js";

export const registerAtlasTaskCreateTool = (server: McpServer) => {
  registerTool(
    server,
    "atlas_task_create",
    "Creates a new task or multiple tasks in the system with detailed specifications, categorization, and dependency tracking",
    AtlasTaskCreateSchemaShape,
    atlasCreateTask,
    createToolMetadata({
      examples: [
        createToolExample(
          {
            mode: "single",
            projectId: "proj_ms_migration",
            title: "Design API Gateway Architecture",
            description:
              "Create a detailed architecture diagram and specifications for the API gateway that will route requests to appropriate microservices, handle authentication, and implement rate limiting",
            priority: "high",
            status: "todo",
            tags: ["architecture", "api", "gateway"],
            completionRequirements:
              "Complete architecture diagram with data flow, scaling strategy, and disaster recovery considerations. Implementation specifications must include authentication flow and rate limiting algorithms",
            outputFormat:
              "Architecture diagram (PDF), Technical specifications document (Markdown), Implementation roadmap",
            taskType: "research",
          },
          `{
            "id": "task_api_gateway",
            "projectId": "proj_ms_migration",
            "title": "Design API Gateway Architecture",
            "description": "Create a detailed architecture diagram and specifications for the API gateway that will route requests to appropriate microservices, handle authentication, and implement rate limiting",
            "priority": "high",
            "status": "todo",
            "assignedTo": null,
            "urls": [],
            "tags": ["architecture", "api", "gateway"],
            "completionRequirements": "Complete architecture diagram with data flow, scaling strategy, and disaster recovery considerations. Implementation specifications must include authentication flow and rate limiting algorithms",
            "outputFormat": "Architecture diagram (PDF), Technical specifications document (Markdown), Implementation roadmap",
            "taskType": "research",
            "createdAt": "2025-03-23T10:11:24.123Z",
            "updatedAt": "2025-03-23T10:11:24.123Z"
          }`,
          "Create a high-priority research task with specific completion criteria under an existing project",
        ),
        createToolExample(
          {
            mode: "bulk",
            tasks: [
              {
                projectId: "proj_graphql",
                title: "Set up GraphQL schema and resolver structure",
                description:
                  "Create the foundation for our GraphQL API by defining the base schema structure, resolver patterns, and integration with existing data sources",
                priority: "high",
                tags: ["graphql", "schema", "foundation"],
                completionRequirements:
                  "Working schema structure with type definitions for core entities. Base resolver pattern implemented with at least one full query path to the database.",
                outputFormat:
                  "TypeScript code implementing the schema and resolvers with documentation",
                taskType: "generation",
              },
              {
                projectId: "proj_graphql",
                title: "Implement authentication and authorization",
                description:
                  "Add authentication and authorization to the GraphQL API using JWT tokens and directive-based permission controls",
                status: "backlog",
                tags: ["auth", "security", "graphql"],
                completionRequirements:
                  "Authentication middleware and directive implemented. All resolvers protected with appropriate permission checks.",
                outputFormat:
                  "TypeScript code with tests demonstrating security controls",
                taskType: "generation",
              },
            ],
          },
          `{
            "success": true,
            "message": "Successfully created 2 tasks",
            "created": [
              {
                "id": "task_graphql_schema",
                "projectId": "proj_graphql",
                "title": "Set up GraphQL schema and resolver structure",
                "description": "Create the foundation for our GraphQL API by defining the base schema structure, resolver patterns, and integration with existing data sources",
                "priority": "high",
                "status": "todo",
                "assignedTo": null,
                "urls": [],
                "tags": ["graphql", "schema", "foundation"],
                "completionRequirements": "Working schema structure with type definitions for core entities. Base resolver pattern implemented with at least one full query path to the database.",
                "outputFormat": "TypeScript code implementing the schema and resolvers with documentation",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.123Z",
                "updatedAt": "2025-03-23T10:11:24.123Z"
              },
              {
                "id": "task_auth",
                "projectId": "proj_graphql",
                "title": "Implement authentication and authorization",
                "description": "Add authentication and authorization to the GraphQL API using JWT tokens and directive-based permission controls",
                "priority": "medium",
                "status": "backlog",
                "assignedTo": null,
                "urls": [],
                "tags": ["auth", "security", "graphql"],
                "completionRequirements": "Authentication middleware and directive implemented. All resolvers protected with appropriate permission checks.",
                "outputFormat": "TypeScript code with tests demonstrating security controls",
                "taskType": "generation",
                "createdAt": "2025-03-23T10:11:24.456Z",
                "updatedAt": "2025-03-23T10:11:24.456Z"
              }
            ],
            "errors": []
          }`,
          "Batch-initialize multiple specialized tasks with clear dependencies and technical requirements",
        ),
      ],
      requiredPermission: "task:create",
      returnSchema: z.union([
        // Single task response
        z.object({
          id: z.string().describe("Task ID"),
          projectId: z.string().describe("Parent project ID"),
          title: z.string().describe("Task title"),
          description: z.string().describe("Task description"),
          priority: z
            .enum([
              PriorityLevel.LOW,
              PriorityLevel.MEDIUM,
              PriorityLevel.HIGH,
              PriorityLevel.CRITICAL,
            ])
            .describe("Importance level"),
          status: z
            .enum([
              TaskStatus.BACKLOG,
              TaskStatus.TODO,
              TaskStatus.IN_PROGRESS,
              TaskStatus.COMPLETED,
            ])
            .describe("Task status"),
          assignedTo: z
            .string()
            .nullable()
            .describe("ID of entity responsible for completion"),
          urls: z
            .array(
              z.object({
                title: z.string(),
                url: z.string(),
              }),
            )
            .describe("Reference materials"),
          tags: z.array(z.string()).describe("Organizational labels"),
          completionRequirements: z.string().describe("Completion criteria"),
          outputFormat: z.string().describe("Deliverable format"),
          taskType: z.string().describe("Task classification"),
          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("Task ID"),
                projectId: z.string().describe("Parent project ID"),
                title: z.string().describe("Task title"),
                description: z.string().describe("Task description"),
                priority: z
                  .enum([
                    PriorityLevel.LOW,
                    PriorityLevel.MEDIUM,
                    PriorityLevel.HIGH,
                    PriorityLevel.CRITICAL,
                  ])
                  .describe("Importance level"),
                status: z
                  .enum([
                    TaskStatus.BACKLOG,
                    TaskStatus.TODO,
                    TaskStatus.IN_PROGRESS,
                    TaskStatus.COMPLETED,
                  ])
                  .describe("Task status"),
                assignedTo: z
                  .string()
                  .nullable()
                  .describe("ID of entity responsible for completion"),
                urls: z
                  .array(
                    z.object({
                      title: z.string(),
                      url: z.string(),
                    }),
                  )
                  .describe("Reference materials"),
                tags: z.array(z.string()).describe("Organizational labels"),
                completionRequirements: z
                  .string()
                  .describe("Completion criteria"),
                outputFormat: z.string().describe("Deliverable format"),
                taskType: z.string().describe("Task classification"),
                createdAt: z.string().describe("Creation timestamp"),
                updatedAt: z.string().describe("Last update timestamp"),
              }),
            )
            .describe("Created tasks"),
          errors: z
            .array(
              z.object({
                index: z.number().describe("Index in the tasks array"),
                task: z.any().describe("Original task 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: 15, // 15 requests per minute (either single or bulk)
      },
    }),
  );
};

```

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

```typescript
import { z } from "zod";
import {
  createKnowledgeDomainEnum,
  createResponseFormatEnum,
  ResponseFormat,
} from "../../../types/mcp.js";

/**
 * Zod schema defining the structure for a single sub-topic provided as input
 * to the deep research tool.
 */
export const DeepResearchSubTopicSchema = z.object({
  /** A focused, well-defined sub-topic or precise question to investigate. */
  question: z
    .string()
    .min(1)
    .describe(
      "A focused, well-defined sub-topic or precise question to investigate. Effective research requires clear, bounded inquiries rather than overly broad topics.",
    ),
  /** Concise, targeted search queries or specific keywords relevant to this sub-topic. */
  initialSearchQueries: z
    .array(z.string())
    .optional()
    .describe(
      "Concise, targeted search queries or specific keywords relevant to this sub-topic. Effective deep research relies on precise, focused queries rather than broad terms.",
    ),
  /** Optional client-provided ID for the knowledge node representing this sub-topic. */
  nodeId: z
    .string()
    .optional()
    .describe(
      "Optional client-provided ID for this sub-topic knowledge node. Useful for maintaining consistent cross-referencing across research efforts.",
    ),
  /** Strategic priority level for the task created for this sub-topic. */
  priority: z
    .enum(["low", "medium", "high", "critical"])
    .optional()
    .describe(
      "Strategic priority level for the task created for this sub-topic. Helps organize the research workflow by importance and urgency.",
    ),
  /** Optional assignee ID for the task created for this sub-topic. */
  assignedTo: z
    .string()
    .optional()
    .describe(
      "Optional assignee ID for the task created for this sub-topic. Enables clear ownership and accountability for specific research areas.",
    ),
  /** Workflow status for the task created for this sub-topic. */
  initialStatus: z
    .enum(["backlog", "todo", "in-progress", "completed"])
    .optional()
    .default("todo")
    .describe(
      "Workflow status for the task created for this sub-topic (default: todo). Facilitates research progression tracking across multiple inquiry areas.",
    ),
});

/**
 * TypeScript type inferred from `DeepResearchSubTopicSchema`. Represents a single sub-topic input.
 */
export type DeepResearchSubTopic = z.infer<typeof DeepResearchSubTopicSchema>;

/**
 * Defines the shape of the input parameters for the `atlas_deep_research` tool.
 * This structure is used to build the final Zod schema.
 */
export const AtlasDeepResearchSchemaShape = {
  /** Organizational parent project ID for contextualizing this research within broader objectives. */
  projectId: z
    .string()
    .describe(
      "Organizational parent project ID for contextualizing this research within broader objectives (required). Essential for proper knowledge graph relationships.",
    ),
  researchTopic: z
    .string()
    .min(1)
    .describe(
      "The primary, overarching topic or central question driving this deep research initiative (required). Should be substantive yet focused enough to yield actionable insights.",
    ),
  /** Clearly articulated objective or specific outcome this research aims to achieve. */
  researchGoal: z
    .string()
    .min(1)
    .describe(
      "Clearly articulated objective or specific outcome this research aims to achieve (required). Defines what successful research completion looks like.",
    ),
  /** Strategic boundary definition clarifying research inclusions and exclusions. */
  scopeDefinition: z
    .string()
    .optional()
    .describe(
      "Strategic boundary definition clarifying research inclusions and exclusions. Prevents scope creep and maintains research focus on high-value areas.",
    ),
  /** Structured decomposition of the main topic into discrete, manageable sub-questions or investigation areas. */
  subTopics: z
    .array(DeepResearchSubTopicSchema)
    .min(1)
    .describe(
      "Structured decomposition of the main topic into discrete, manageable sub-questions or investigation areas. Effective research requires breaking complex topics into component inquiries.",
    ),
  /** Knowledge domain classification for the overall research topic. */
  researchDomain: createKnowledgeDomainEnum()
    .or(z.string())
    .optional()
    .describe(
      "Knowledge domain classification for the overall research topic (e.g., 'technical', 'business', 'scientific'). Enables better categorization and retrieval within the knowledge management system.",
    ),
  /** Semantic categorization tags for improved searchability and relationship identification. */
  initialTags: z
    .array(z.string())
    .optional()
    .describe(
      "Semantic categorization tags for improved searchability and relationship identification. Facilitates connecting this research to related knowledge areas.",
    ),
  /** Unique identifier for the main research plan knowledge node. */
  planNodeId: z
    .string()
    .optional()
    .describe(
      "Unique identifier for the main research plan knowledge node. Enables programmatic reference to this research plan in future operations.",
    ),
  /** Output format specification for the tool response. */
  responseFormat: createResponseFormatEnum()
    .optional()
    .default(ResponseFormat.FORMATTED)
    .describe(
      "Output format specification for the tool response. Controls whether the response is human-readable ('formatted') or machine-processable ('json').",
    ),
  /** Task generation control flag for research operationalization. */
  createTasks: z
    .boolean()
    .optional()
    .default(true)
    .describe(
      "Task generation control flag for research operationalization (default: true). When enabled, creates trackable tasks for each sub-topic to facilitate systematic investigation.",
    ),
} as const;

/**
 * The complete Zod schema for validating the input arguments of the `atlas_deep_research` tool.
 */
export const AtlasDeepResearchInputSchema = z.object(
  AtlasDeepResearchSchemaShape,
);

/**
 * TypeScript type inferred from `AtlasDeepResearchInputSchema`. Represents the validated input object.
 */
export type AtlasDeepResearchInput = z.infer<
  typeof AtlasDeepResearchInputSchema
>;

/**
 * Zod schema defining the structure for representing a created sub-topic knowledge node
 * in the tool's output.
 */
export const DeepResearchSubTopicNodeResultSchema = z.object({
  /** The formulated sub-topic question representing a discrete research inquiry. */
  question: z
    .string()
    .describe(
      "The formulated sub-topic question representing a discrete research inquiry. Forms the foundation for focused knowledge gathering.",
    ),
  /** Unique identifier for the knowledge node containing insights related to this sub-topic. */
  nodeId: z
    .string()
    .describe(
      "Unique identifier for the knowledge node containing insights related to this sub-topic. Essential for cross-referencing and knowledge relationship mapping.",
    ),
  /** Reference to the actionable task entity created to investigate this sub-topic. */
  taskId: z
    .string()
    .optional()
    .describe(
      "Reference to the actionable task entity created to investigate this sub-topic, if applicable. Links knowledge goals with operational workflow.",
    ),
  /** Precision-targeted search queries used to initiate investigation of this sub-topic. */
  initialSearchQueries: z
    .array(z.string())
    .optional()
    .describe(
      "Precision-targeted search queries used to initiate investigation of this sub-topic. Effective deep research begins with carefully crafted, specific queries.",
    ),
});

/**
 * TypeScript type inferred from `DeepResearchSubTopicNodeResultSchema`. Represents a single sub-topic node result.
 */
export type DeepResearchSubTopicNodeResult = z.infer<
  typeof DeepResearchSubTopicNodeResultSchema
>;

/**
 * Interface defining the expected output structure returned by the core `deepResearch` function.
 */
export interface DeepResearchResult {
  /** Execution status indicator for the overall research plan creation operation. */
  success: boolean;
  /** Comprehensive summary of the research plan creation outcome with relevant details. */
  message: string;
  /** Unique reference identifier for the root knowledge node containing the complete research plan. */
  planNodeId: string;
  /** Semantic categorization markers applied to the root research plan for improved discoverability. */
  initialTags?: string[];
  /** Structured collection of created knowledge nodes and associated tasks representing discrete research areas. */
  subTopicNodes: DeepResearchSubTopicNodeResult[];
  /** Operational workflow status indicating whether actionable tasks were created for research execution. */
  tasksCreated: boolean;
}

/**
 * Zod schema defining the structure of the output returned by the `atlas_deep_research` tool handler.
 * This is used for potential validation or type checking of the final tool response content.
 */
export const AtlasDeepResearchOutputSchema = z.object({
  /** Status indicator reflecting whether the research plan creation completed successfully. */
  success: z
    .boolean()
    .describe(
      "Status indicator reflecting whether the research plan creation completed successfully. Critical for error handling and flow control.",
    ),
  /** Informative summary describing the research plan creation outcome with actionable details. */
  message: z
    .string()
    .describe(
      "Informative summary describing the research plan creation outcome with actionable details. Provides context for next steps.",
    ),
  /** Unique reference ID for the core knowledge node containing the comprehensive research plan. */
  planNodeId: z
    .string()
    .describe(
      "Unique reference ID for the core knowledge node containing the comprehensive research plan. Essential for future references to this research initiative.",
    ),
  /** Semantic classification markers applied to the research plan for improved categorical organization. */
  initialTags: z
    .array(z.string())
    .optional()
    .describe(
      "Semantic classification markers applied to the research plan for improved categorical organization. Facilitates knowledge discovery and relationship mapping.",
    ),
  /** Structured collection of generated knowledge nodes and workflow tasks for each research sub-area. */
  subTopicNodes: z
    .array(DeepResearchSubTopicNodeResultSchema)
    .describe(
      "Structured collection of generated knowledge nodes and workflow tasks for each research sub-area. Provides the complete map of the created research knowledge structure.",
    ),
  /** Task creation status indicating whether operational workflow items were generated. */
  tasksCreated: z
    .boolean()
    .describe(
      "Task creation status indicating whether operational workflow items were generated. Confirms proper integration with the task management system.",
    ),
});

/**
 * TypeScript type inferred from `AtlasDeepResearchOutputSchema`. Represents the structured output of the tool.
 */
export type AtlasDeepResearchOutput = z.infer<
  typeof AtlasDeepResearchOutputSchema
>;

```

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

```typescript
import { nanoid } from "nanoid";
import { KnowledgeService } from "../../../services/neo4j/knowledgeService.js";
import { ProjectService } from "../../../services/neo4j/projectService.js";
import { TaskService } from "../../../services/neo4j/taskService.js"; // Import TaskService
import { BaseErrorCode, McpError } from "../../../types/errors.js";
import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
import { sanitization } from "../../../utils/security/sanitization.js";
import {
  AtlasDeepResearchInput,
  DeepResearchResult,
  DeepResearchSubTopicNodeResult,
} from "./types.js";

/**
 * Generates a unique ID suitable for knowledge nodes using nanoid.
 * Includes a prefix for better identification (e.g., 'plan', 'sub').
 *
 * @param prefix - The prefix to use for the ID (defaults to 'knw').
 * @returns A unique ID string (e.g., 'plan_aBcDeFgHiJkL').
 */
function generateKnowledgeId(prefix: string = "knw"): string {
  return `${prefix}_${nanoid(12)}`; // Using 12 characters for increased uniqueness
}

/**
 * Core implementation logic for the `atlas_deep_research` tool.
 * This function orchestrates the creation of a hierarchical knowledge structure
 * in Neo4j to represent a research plan based on the provided input.
 * It creates a root node for the overall plan and child nodes for each sub-topic.
 *
 * @param input - The validated input object conforming to `AtlasDeepResearchInput`.
 * @returns A promise resolving to a `DeepResearchResult` object containing details
 *          about the created nodes/tasks and the operation's success status.
 * @throws {McpError} If the project ID is invalid, or if any database operation fails.
 */
export async function deepResearch(
  input: AtlasDeepResearchInput,
): Promise<DeepResearchResult> {
  const reqContext = requestContextService.createRequestContext({
    operation: "deepResearch",
    projectId: input.projectId,
    researchTopic: input.researchTopic,
  });
  logger.info(
    `Initiating deep research plan creation for project ID: ${input.projectId}, Topic: "${input.researchTopic}"`,
    reqContext,
  );

  try {
    // 1. Validate Project Existence
    // Ensure the specified project exists before proceeding.
    const project = await ProjectService.getProjectById(input.projectId);
    if (!project) {
      throw new McpError(
        BaseErrorCode.NOT_FOUND,
        `Project with ID "${input.projectId}" not found. Cannot create research plan.`,
      );
    }
    logger.debug(
      `Project validation successful for ID: ${input.projectId}`,
      reqContext,
    );

    // 2. Prepare Root Research Plan Node Data
    const planNodeId = input.planNodeId || generateKnowledgeId("plan");
    const rootTextParts: string[] = [
      `Research Plan: ${sanitization.sanitizeString(input.researchTopic)}`,
      `Goal: ${sanitization.sanitizeString(input.researchGoal)}`,
    ];
    if (input.scopeDefinition) {
      rootTextParts.push(
        `Scope: ${sanitization.sanitizeString(input.scopeDefinition)}`,
      );
    }
    const rootText = rootTextParts.join("\n\n"); // Combine parts into the main text content

    // Define tags for the root node
    const rootTags = [
      "research-plan",
      "research-root",
      "status:active", // Initialize the plan as active
      `topic:${sanitization
        .sanitizeString(input.researchTopic)
        .toLowerCase()
        .replace(/\s+/g, "-") // Convert topic to a URL-friendly tag format
        .slice(0, 50)}`, // Limit tag length
      ...(input.initialTags || []), // Include any user-provided initial tags
    ];

    // 3. Create Root Research Plan Node and link to Project
    // Assuming KnowledgeService.addKnowledge handles linking if projectId is provided,
    // or we might need a specific method like addKnowledgeAndLinkToProject.
    // For now, assume addKnowledge creates the node and links it via projectId.
    // A more robust approach might involve explicit relationship creation.
    logger.debug(
      `Attempting to create root research plan node with ID: ${planNodeId}`,
      { ...reqContext, planNodeId },
    );
    await KnowledgeService.addKnowledge({
      id: planNodeId,
      projectId: input.projectId,
      text: rootText,
      domain: input.researchDomain || "research",
      tags: rootTags,
      citations: [],
    });
    // If explicit linking is needed:
    // await KnowledgeService.linkKnowledgeToProject(planNodeId, input.projectId, 'CONTAINS_PLAN');
    logger.info(
      `Root research plan node ${planNodeId} created and associated with project.`,
      { ...reqContext, planNodeId },
    );

    // 4. Create Knowledge Nodes and Optional Tasks for Each Sub-Topic
    const createdSubTopicNodes: DeepResearchSubTopicNodeResult[] = [];
    const tasksToCreate = input.createTasks ?? true; // Default to true if not specified
    logger.debug(
      `Processing ${input.subTopics.length} sub-topics to create knowledge nodes ${
        tasksToCreate ? "and tasks" : ""
      }.`,
      {
        ...reqContext,
        subTopicCount: input.subTopics.length,
        willCreateTasks: tasksToCreate,
      },
    );

    for (const subTopic of input.subTopics) {
      const subTopicNodeId = subTopic.nodeId || generateKnowledgeId("sub");
      let createdTaskId: string | undefined = undefined;

      // Sanitize search queries before joining
      const searchQueriesString = (subTopic.initialSearchQueries || [])
        .map((kw) => sanitization.sanitizeString(kw))
        .join(", ");
      // Construct the text content for the sub-topic node
      const subTopicText = `Research Question: ${sanitization.sanitizeString(
        subTopic.question,
      )}\n\nInitial Search Queries: ${searchQueriesString || "None provided"}`;

      // Define tags for the sub-topic node
      const subTopicTags = [
        "research-subtopic",
        "status:pending", // Initialize sub-topics as pending
        // `parent-plan:${planNodeId}`, // Replaced by relationship if implemented
        ...(subTopic.initialSearchQueries?.map(
          (kw: string) =>
            `search-query:${sanitization
              .sanitizeString(kw) // Create tags for each search query
              .toLowerCase()
              .replace(/\s+/g, "-")
              .slice(0, 50)}`,
        ) || []),
      ];

      logger.debug(
        `Attempting to create sub-topic node with ID: ${subTopicNodeId} for question: "${subTopic.question}"`,
        { ...reqContext, subTopicNodeId, question: subTopic.question },
      );
      // Create the sub-topic knowledge node and link it to the parent plan node
      // Assuming addKnowledge links to project, now link to parent knowledge node
      await KnowledgeService.addKnowledge({
        id: subTopicNodeId,
        projectId: input.projectId, // Associate with the same project
        text: subTopicText,
        domain: input.researchDomain || "research", // Inherit domain from the root plan
        tags: subTopicTags,
        citations: [], // Sub-topics also start with no citations
      });
      // Explicitly link sub-topic to parent plan node
      await KnowledgeService.linkKnowledgeToKnowledge(
        subTopicNodeId,
        planNodeId,
        "IS_SUBTOPIC_OF", // Relationship type from child to parent
      );
      logger.info(
        `Sub-topic node ${subTopicNodeId} created and linked to plan ${planNodeId}.`,
        { ...reqContext, subTopicNodeId, parentPlanNodeId: planNodeId },
      );

      // Create Task if requested
      if (tasksToCreate) {
        logger.debug(`Creating task for sub-topic node ${subTopicNodeId}`, {
          ...reqContext,
          subTopicNodeId,
        });
        const taskTitle = `Research: ${sanitization.sanitizeString(
          subTopic.question,
        )}`;
        const taskDescription = `Investigate the research question: "${sanitization.sanitizeString(
          subTopic.question,
        )}"\n\nInitial Search Queries: ${
          searchQueriesString || "None provided"
        }\n\nAssociated Knowledge Node: ${subTopicNodeId}`;

        // Use TaskService to create the task and link it to the project
        const taskResult = await TaskService.createTask({
          projectId: input.projectId,
          title: taskTitle.slice(0, 150), // Ensure title length constraint
          description: taskDescription,
          priority: subTopic.priority || "medium",
          status: subTopic.initialStatus || "todo",
          assignedTo: subTopic.assignedTo,
          completionRequirements: `Gather relevant information and synthesize findings related to the research question. Update associated knowledge node ${subTopicNodeId}.`,
          outputFormat:
            "Update to knowledge node, potentially new linked knowledge items.",
          taskType: "research", // Specific task type
          // tags: [`research-task`, `plan:${planNodeId}`], // Optional tags for the task
        });

        createdTaskId = taskResult.id;
        logger.info(
          `Task ${createdTaskId} created for sub-topic ${subTopicNodeId}.`,
          { ...reqContext, createdTaskId, subTopicNodeId },
        );

        // Link Task to the Sub-Topic Knowledge Node
        await TaskService.linkTaskToKnowledge(
          createdTaskId,
          subTopicNodeId,
          "ADDRESSES", // Relationship: Task ADDRESSES Knowledge Node
        );
        logger.debug(
          `Linked task ${createdTaskId} to knowledge node ${subTopicNodeId} with ADDRESSES relationship.`,
          { ...reqContext, createdTaskId, subTopicNodeId },
        );
      }

      // Record the details of the created sub-topic node and task
      createdSubTopicNodes.push({
        question: subTopic.question,
        nodeId: subTopicNodeId,
        taskId: createdTaskId, // Include task ID if created
        initialSearchQueries: subTopic.initialSearchQueries || [],
      });
    }

    // 5. Assemble and Return the Result
    const taskMessage = tasksToCreate
      ? `and ${createdSubTopicNodes.length} associated tasks`
      : "";
    const successMessage = `Successfully created deep research plan "${input.researchTopic}" with root research plan node ${planNodeId}, ${createdSubTopicNodes.length} sub-topic nodes ${taskMessage}.`;
    logger.info(successMessage, {
      ...reqContext,
      planNodeId,
      subTopicNodeCount: createdSubTopicNodes.length,
      tasksCreatedCount: tasksToCreate ? createdSubTopicNodes.length : 0,
    });

    return {
      success: true,
      message: successMessage,
      planNodeId: planNodeId,
      initialTags: input.initialTags || [], // Return the initial tags applied to the root
      subTopicNodes: createdSubTopicNodes, // Return details of created sub-topic nodes and tasks
      tasksCreated: tasksToCreate, // Indicate if tasks were created
    };
  } catch (error) {
    // Log the error with context
    const errorContextDetails = {
      // errorMessage is part of the error object passed to logger.error
      // stack is part of the error object passed to logger.error
      projectId: input.projectId, // Already in reqContext
      researchTopic: input.researchTopic, // Already in reqContext
    };
    logger.error(
      "Error occurred during deep research plan creation",
      error as Error,
      { ...reqContext, ...errorContextDetails },
    );

    // Re-throw McpError instances directly
    if (error instanceof McpError) {
      throw error;
    }
    // Wrap unexpected errors in a generic McpError
    throw new McpError(
      BaseErrorCode.INTERNAL_ERROR,
      `Failed to create deep research plan (Project: ${input.projectId}, Topic: "${input.researchTopic}"): ${
        error instanceof Error ? error.message : String(error)
      }`,
    );
  }
}

```

--------------------------------------------------------------------------------
/examples/deep-research-example/covington_community_grant_research.md:
--------------------------------------------------------------------------------

```markdown
Prompt:

# Grant Research Task: Covington, KY Community Projects

Conduct comprehensive research on publicly available grants for solo-owned community projects in Covington, Kentucky using atlas_deep_research to gather information. Focus on funding opportunities specifically suitable for individual owners of community gardens and similar local initiatives. Identify grant programs from government sources (federal, state, and local), private foundations, and community organizations that support urban agriculture and neighborhood improvement projects.

Research should prioritize:

- Current open application periods and upcoming deadlines
- Grant amounts and funding cycles
- Eligibility requirements specific to individual applicants rather than organizations
- Any special programs targeting the Covington area or Northern Kentucky region
- Application processes and documentation requirements
- Past successful community garden projects in the area

Include information on matching grant opportunities and any technical assistance programs available to support the application process. Perform extensive research and provide a detailed report on your findings in /Users/casey/Developer/github/atlas-mcp-agent/workspace.

Use the perplexity search tool for LLM augmented searching (search-augmented-generation); use the firecrawl tools for web scraping when necessary. Keep the atlas db completely up to date with all details.

Perform extensive research. Include specific details about the grants. Include details on how to apply for the grants.

Start by clearing the db.

---

# Grant Research Report: Solo-Owned Community Projects in Covington, KY

**Date:** April 1, 2025
**Project:** Grant Research: Covington, KY Community Projects (ID: `proj_a67039840514408386ec549c53668a8b`)

## Executive Summary

This report details findings on grant opportunities for individuals seeking to start or manage community projects, such as community gardens, in Covington, Kentucky. Research indicates that **direct grant funding for solo individuals is limited**. Most federal, state, and foundation grants require applicants to be registered non-profits, government entities, schools, or tribes.

However, several viable pathways exist, primarily through **collaboration and partnership**:

1.  **Forming Informal Groups:** Applying as a small, resident-led group (even informal ones) is often accepted, particularly for local programs like the Covington Neighborhood Grant.
2.  **Partnering with Existing Organizations:** Collaborating with established non-profits (like The Center for Great Neighborhoods) or schools can provide access to grants requiring organizational status.
3.  **Fiscal Sponsorship:** Utilizing a fiscal sponsor allows individuals to apply for grants under the umbrella of a registered non-profit.

The most promising local opportunity is the **Covington Neighborhood Grant Program**, facilitated by The Center for Great Neighborhoods, which supports resident-led group projects. Technical assistance for grant writing is available through various state and local organizations.

## Key Grant Opportunities & Programs

### 1. Covington Neighborhood Grant Program

- **Funding:** $1,400 - $5,000 per project.
- **Eligibility:** Resident-led groups (formal associations, emerging groups, or informal neighbor collaborations). Individuals must partner or form a group.
- **Focus:** Neighborhood beautification, blight removal, community events, public space improvements (including gardens, landscaping).
- **Application:** Process involves meeting with The Center for Great Neighborhoods (CfGN) for guidance, submitting a detailed application/budget. CfGN assists applicants.
- **Deadline:** FY25 cycle closed Sept 30, 2024. Future cycles TBA.
- **Source/Contact:**
  - The Center for Great Neighborhoods (CfGN): [https://www.greatneighborhoods.org](https://www.greatneighborhoods.org)
  - Program Info: Often via City of Covington documents or direct contact with CfGN.
  - CfGN Contact: Cate Douglas, [email protected], (859) 547-5550.
- _(Atlas Sources: know_a62b36b9..., know_46e966ad..., know_194abba6..., know_ddae3b81f..., know_1d2b459a..., know_8a77ae38..., know_cdaf9b90...)_

### 2. Kentucky State University Small-Scale Farm Grant Program

- **Funding:** Up to $5,000 per household.
- **Eligibility:** Small-scale farms (<$250k annual sales), potentially including urban farms. Individual farmers may be eligible. Priority for limited-resource, women, minority farmers.
- **Focus:** Improving farm operations, value-added enterprises, organic/specialty crops, agroforestry.
- **Application:** Submit detailed farm improvement plan & budget via email/mail.
- **Deadline:** Previous cycle closed Dec 1, 2024. Future cycles TBA.
- **Source/Contact:**
  - Official Program Page: [https://www.kysu.edu/academics/college-ahnr/school-of-anr/co-op/small-scale-farm-grant-program.php](https://www.kysu.edu/academics/college-ahnr/school-of-anr/co-op/small-scale-farm-grant-program.php)
  - Contact/Submission: M. Allison Noel, [email protected], Kentucky State University, 400 East Main Street, CEB-218, Frankfort, KY 40601.
- _(Atlas Sources: know_46e966ad..., know_3005a083..., know_0dc8d825...)_

### 3. GrantWatch Listings (Potential Direct Individual Grants)

- **GrantWatch Website:** [https://www.grantwatch.com](https://www.grantwatch.com)
- **Urban Gardeners Grant:** Up to $5k potentially for individuals/orgs (for-profit focus). Verification needed via GrantWatch.
- **KY Agricultural Producer Grant:** Up to $5k potentially for specific producer categories (BIPOC, female, etc.). Verification needed via GrantWatch.
- **Application/Deadline:** Recurring/unspecified. Check GrantWatch.com for current status and specific application details.
- _(Atlas Sources: know_8f2cb3e98..., know_10e0f081..., know_4c3d6e43...)_

### 4. USDA Repair Loans & Grants (Indirect Support)

- **Funding:** Loans up to $40k; Grants up to $10k (for elderly 62+ removing hazards).
- **Eligibility:** Low-income homeowners (individuals).
- **Focus:** Home repairs/modernization, hazard removal. Not garden-specific but could fund related property repairs. Check USDA local office for details.
- _(Atlas Sources: know_194abba6...)_

### 5. USDA Farm Service Agency (FSA) Loans (Not Grants)

- **Funding:** Direct Operating Loans & Microloans (up to $50k).
- **Eligibility:** Individual small-scale urban farmers/gardeners.
- **Focus:** Startup costs (equipment, seeds, etc.). Requires repayment. Check USDA FSA local office for details.
- _(Atlas Sources: know_a62b36b9...)_

### 6. Pure Farmland Grants / Alternatives

- **Pure Farmland:** Specific grant not found in recent searches; may be inactive or misnamed. Past grants ($1k+) supported Covington gardens (e.g., Redden Gardens). Check for recurrence.
- **Alternatives:**
  - GroMoreGood Grassroots Grant (Scotts): $1.5k, youth focus, Jan 30 deadline. Check Scotts Miracle-Gro Foundation website.
  - Columbus Foundation Grants: $1.5k, Central OH focus, Mar 21 deadline. Check geographic eligibility.
- _(Atlas Sources: know_1d2b459a..., know_ed478734...)_

### 7. Other Federal/State/Foundation Grants (Partnership Required)

- **Federal (USDA Urban Ag, People's Garden, Community Facilities):** Primarily target organizations. Individuals need to partner. Check specific USDA program websites.
- **State (KY Urban Forestry):** Requires partnership with non-profits/local govt. Check KY Division of Forestry.
- **Foundations (Horizon Community Funds, Greater Cincinnati Foundation, National Garden Grants):** Fund non-profits or schools. Individuals need to partner or use fiscal sponsors. Check foundation websites.
- _(Atlas Sources: know_33bca161..., know_490fcce4..., know_ddae3b81f..., know_214bee7f...)_

## Matching Grant Opportunities

- Direct matching grants for individuals are unlikely.
- The **Kentucky G.R.A.N.T. Program** offers state matching funds for federal grants but requires county, city, or 501(c)(3) status. Partnership is necessary for individuals/groups. Check KY Cabinet for Economic Development website.
- Other programs (e.g., USDA People's Gardens, some state environmental grants) may require local matches and partnerships.
- **Key Strategy:** Partnering with eligible entities (esp. CfGN) is the primary way to access matching funds.
- _(Atlas Source: know_7ad86d22...)_

## Technical Assistance & Grant Writing Support

Several resources can assist individuals/groups:

- **The Center for Great Neighborhoods (Covington):** Direct assistance for the Neighborhood Grant Program. ([https://www.greatneighborhoods.org](https://www.greatneighborhoods.org))
- **Kentucky Nonprofit Network (KNN):** Grant writing workshops in Covington. (URL not found in search)
- **Grant Ready Kentucky (GRKY):** Statewide direct assistance for federal grants. ([https://grantreadyky.org](https://grantreadyky.org))
- **Kentucky SBDC (Covington):** Free coaching for nonprofits/entrepreneurs. (Official URL not found; related SBA KY page: [https://www.sba.gov/district/kentucky](https://www.sba.gov/district/kentucky))
- **Appalachian Community Fund (ACF):** TA grants for training in Appalachian KY counties. (Official URL not found)
- **USDA Rural Development:** Grants focused on cooperative development and capacity building. Check USDA RD website.
- **KY Farm to School Network:** TA specifically for school gardens. ([https://www.kyfarmtoschool.com](https://www.kyfarmtoschool.com))
- _(Atlas Sources: know_114ca14f..., know_4c3d6e43...)_

## Examples of Funded Covington Projects

Successful local projects often involve resident groups and partnerships:

- **Redden Gardens (Eastside):** Allotment garden with CfGN partnership.
- **Orchard Park (Westside):** Urban farm/community space created by 'Grow the Cov' group with CfGN/city support.
- **Riddle-Yates Community Garden:** Covington's oldest, managed by CfGN.
- **Make Goebel Great:** Resident-led park improvement project with city collaboration.
- _(Atlas Source: know_bc417d3a...)_

## Conclusion & Recommendation

Funding a solo-led community project in Covington requires strategic planning. While direct individual grants are scarce, opportunities significantly increase through collaboration. **The most recommended approach for an individual is to partner with neighbors to form a small group or work directly with The Center for Great Neighborhoods ([https://www.greatneighborhoods.org](https://www.greatneighborhoods.org)).** CfGN can provide guidance, assist with applications for the Neighborhood Grant Program, and potentially act as a fiscal sponsor or connector for other funding sources requiring organizational status. Exploring the KYSU Small-Scale Farm Grant ([https://www.kysu.edu/academics/college-ahnr/school-of-anr/co-op/small-scale-farm-grant-program.php](https://www.kysu.edu/academics/college-ahnr/school-of-anr/co-op/small-scale-farm-grant-program.php)) or specific GrantWatch listings ([https://www.grantwatch.com](https://www.grantwatch.com)) are secondary options if eligibility criteria are met. Leveraging available technical assistance resources (like GRKY: [https://grantreadyky.org](https://grantreadyky.org)) is also highly advised.

---

## Atlas Database Export

For a complete export of the research collected in the Atlas database, including detailed information about each grant opportunity, eligibility criteria, application processes, and contact information, please refer to the file:

[./full-export.json](./full-export.json)

This export contains all structured knowledge nodes created during the research process, including relationships between different funding sources and programs. The database can be imported into other Atlas instances or used for reference when developing grant applications.

```
Page 3/6FirstPrevNextLast