UNPKG

atlas-mcp-server

Version:

ATLAS (Adaptive Task & Logic Automation System): An MCP server enabling LLM agents to manage projects, tasks, and knowledge via a Neo4j-backed, three-tier architecture. Facilitates complex workflow automation and project management through LLM Agents.

184 lines (183 loc) 8.52 kB
import { KnowledgeService, ProjectService, TaskService, } from "../../../services/neo4j/index.js"; import { BaseErrorCode, McpError } from "../../../types/errors.js"; import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService /** * Retrieve and filter project entities based on specified criteria * Provides two query modes: detailed entity retrieval or paginated collection listing * * @param request The project query parameters including filters and pagination controls * @returns Promise resolving to structured project entities with optional related resources */ export async function listProjects(request) { const reqContext = requestContextService.createRequestContext({ toolName: "listProjects", requestMode: request.mode, }); try { const { mode = "all", id, page = 1, limit = 20, includeKnowledge = false, includeTasks = false, taskType, status, } = request; // Parameter validation if (mode === "details" && !id) { throw new McpError(BaseErrorCode.VALIDATION_ERROR, 'Project identifier is required when using mode="details"'); } // Sanitize pagination parameters const validatedPage = Math.max(1, page); const validatedLimit = Math.min(Math.max(1, limit), 100); let projects = []; let total = 0; let totalPages = 0; if (mode === "details") { // Retrieve specific project entity by identifier const projectResult = await ProjectService.getProjectById(id); if (!projectResult) { throw new McpError(BaseErrorCode.NOT_FOUND, `Project with identifier ${id} not found`); } // Cast to the tool's Project type projects = [projectResult]; total = 1; totalPages = 1; } else { // Get paginated list of projects with filters const projectsResult = await ProjectService.getProjects({ status, taskType, page: validatedPage, limit: validatedLimit, }); // Cast each project to the tool's Project type projects = projectsResult.data.map((p) => p); total = projectsResult.total; totalPages = projectsResult.totalPages; } // Process knowledge resource associations if requested if (includeKnowledge && projects.length > 0) { for (const project of projects) { if (mode === "details") { // For detailed view, retrieve comprehensive knowledge resources const knowledgeResult = await KnowledgeService.getKnowledge({ projectId: project.id, // Access directly page: 1, limit: 100, // Reasonable threshold for associated resources }); // Add debug logging logger.info("Knowledge items retrieved", { ...reqContext, projectId: project.id, // Access directly count: knowledgeResult.data.length, firstItem: knowledgeResult.data[0] ? JSON.stringify(knowledgeResult.data[0]) : "none", }); // Map directly, assuming KnowledgeService returns Neo4jKnowledge objects project.knowledge = knowledgeResult.data.map((item) => { // More explicit mapping with debug info logger.debug("Processing knowledge item", { ...reqContext, id: item.id, domain: item.domain, textLength: item.text ? item.text.length : 0, }); // Cast to the tool's Knowledge type return item; }); } else { // For list mode, get abbreviated knowledge items const knowledgeResult = await KnowledgeService.getKnowledge({ projectId: project.id, // Access directly page: 1, limit: 5, // Just a few for summary view }); // Map directly, assuming KnowledgeService returns Neo4jKnowledge objects project.knowledge = knowledgeResult.data.map((item) => { // Cast to the tool's Knowledge type, potentially truncating text const knowledgeItem = item; return { ...knowledgeItem, // Show a preview of the text - increased to 200 characters text: item.text && item.text.length > 200 ? item.text.substring(0, 200) + "... (truncated)" : item.text, }; }); } } } // Process task entity associations if requested if (includeTasks && projects.length > 0) { for (const project of projects) { if (mode === "details") { // For detailed view, retrieve prioritized task entities const tasksResult = await TaskService.getTasks({ projectId: project.id, // Access directly page: 1, limit: 100, // Reasonable threshold for associated entities sortBy: "priority", sortDirection: "desc", }); // Add debug logging logger.info("Tasks retrieved for project", { ...reqContext, projectId: project.id, // Access directly count: tasksResult.data.length, firstItem: tasksResult.data[0] ? JSON.stringify(tasksResult.data[0]) : "none", }); // Map directly, assuming TaskService returns Neo4jTask objects project.tasks = tasksResult.data.map((item) => { // Debug info logger.debug("Processing task item", { ...reqContext, id: item.id, title: item.title, status: item.status, priority: item.priority, }); // Cast to the tool's Task type return item; }); } else { // For list mode, get abbreviated task items const tasksResult = await TaskService.getTasks({ projectId: project.id, // Access directly page: 1, limit: 5, // Just a few for summary view sortBy: "priority", sortDirection: "desc", }); // Map directly, assuming TaskService returns Neo4jTask objects project.tasks = tasksResult.data.map((item) => { // Cast to the tool's Task type return item; }); } } } // Construct the response const response = { projects, total, page: validatedPage, limit: validatedLimit, totalPages, }; logger.info("Project query executed successfully", { ...reqContext, mode, count: projects.length, total, includeKnowledge, includeTasks, }); return response; } catch (error) { logger.error("Project query execution failed", error, reqContext); if (error instanceof McpError) { throw error; } throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to retrieve project entities: ${error instanceof Error ? error.message : String(error)}`); } }