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.
213 lines (212 loc) • 10.8 kB
JavaScript
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 { AtlasTaskCreateSchema } from "./types.js";
import { formatTaskCreateResponse } from "./responseFormat.js";
export const atlasCreateTask = async (input, context) => {
let validatedInput;
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: [],
errors: [],
};
// 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, {
...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"}`);
}
};