@mseep/atlas-mcp-server
Version:
A Model Context Protocol (MCP) server for ATLAS, a Neo4j-powered task management system for LLM Agents - implementing a three-tier architecture (Projects, Tasks, Knowledge) to manage complex workflows.
105 lines (104 loc) • 6.29 kB
JavaScript
import { createFormattedResponse, } from "../../../utils/responseFormatter.js";
/**
* Base response formatter for the `atlas_deep_research` tool.
* This formatter provides a basic structure for the output, primarily using
* the data returned by the core `deepResearch` function.
* It's designed to be used within `formatDeepResearchResponse` which adds
* contextual information from the original tool input.
*/
export const DeepResearchBaseFormatter = {
format: (data) => {
// This base format method only uses the 'data' part of the result.
// Context from the 'input' is added by the calling function below.
if (!data.success) {
// Basic error formatting if the operation failed
return `Error initiating deep research: ${data.message}`;
}
// Start building the Markdown output
const lines = [
`## Deep Research Plan Initiated`,
`**Status:** ${data.message}`, // Display the success message from the core logic
`**Plan Node ID:** \`${data.planNodeId}\``, // Show the ID of the created root node
];
// Add details about the created sub-topic nodes
if (data.subTopicNodes && data.subTopicNodes.length > 0) {
lines.push(`\n### Sub-Topics Created (${data.subTopicNodes.length})${data.tasksCreated ? ' (with Tasks)' : ''}:`);
data.subTopicNodes.forEach((node) => {
const taskInfo = node.taskId ? `\n - **Task ID:** \`${node.taskId}\`` : '';
// Basic info available directly from the result data
lines.push(`- **Question:** ${node.question}\n - **Node ID:** \`${node.nodeId}\`${taskInfo}`
// Note: Initial Search Queries are added by the contextual formatter below
);
});
}
else {
lines.push("\nNo sub-topics were specified or created.");
}
return lines.join("\n"); // Combine lines into a single Markdown string
},
};
/**
* Creates the final formatted `McpToolResponse` for the `atlas_deep_research` tool.
* This function takes the raw result from the core logic (`deepResearch`) and the
* original tool input, then uses a *contextual* formatter to generate the final
* Markdown output. The contextual formatter enhances the base format by including
* details from the input (like topic, goal, scope, tags, and search queries).
*
* @param rawData - The `DeepResearchResult` object returned by the `deepResearch` function.
* @param input - The original `AtlasDeepResearchInput` provided to the tool.
* @returns The final `McpToolResponse` object ready to be sent back to the client.
*/
export function formatDeepResearchResponse(rawData, input) {
// Define a contextual formatter *inside* this function.
// This allows the formatter's `format` method to access the `input` variable via closure.
const contextualFormatter = {
format: (data) => {
// Handle error case first
if (!data.success) {
return `Error initiating deep research: ${data.message}`;
}
// Start building the Markdown output, including details from the input
const lines = [
`## Deep Research Plan Initiated`,
`**Topic:** ${input.researchTopic}`, // Include Topic from input
`**Goal:** ${input.researchGoal}`, // Include Goal from input
];
if (input.scopeDefinition) {
lines.push(`**Scope:** ${input.scopeDefinition}`); // Include Scope if provided
}
lines.push(`**Project ID:** \`${input.projectId}\``); // Include Project ID
if (input.researchDomain) {
lines.push(`**Domain:** ${input.researchDomain}`); // Include Domain if provided
}
lines.push(`**Status:** ${data.message}`); // Status message from result
lines.push(`**Plan Node ID:** \`${data.planNodeId}\``); // Root node ID from result
if (input.initialTags && input.initialTags.length > 0) {
lines.push(`**Initial Tags:** ${input.initialTags.join(', ')}`); // Include initial tags
}
// Add details about sub-topic nodes, including search queries from input
if (data.subTopicNodes && data.subTopicNodes.length > 0) {
lines.push(`\n### Sub-Topics Created (${data.subTopicNodes.length}):`);
data.subTopicNodes.forEach((node) => {
// Find the corresponding sub-topic in the input to retrieve initial search queries
// Find the corresponding sub-topic in the input to retrieve initial search queries and task details
const inputSubTopic = input.subTopics.find((st) => st.question === node.question);
const searchQueries = inputSubTopic?.initialSearchQueries?.join(', ') || 'N/A'; // Format queries or show N/A
const taskInfo = node.taskId ? `\n - **Task ID:** \`${node.taskId}\`` : ''; // Add Task ID if present
const priorityInfo = inputSubTopic?.priority ? `\n - **Task Priority:** ${inputSubTopic.priority}` : '';
const assigneeInfo = inputSubTopic?.assignedTo ? `\n - **Task Assignee:** ${inputSubTopic.assignedTo}` : '';
const statusInfo = inputSubTopic?.initialStatus ? `\n - **Task Status:** ${inputSubTopic.initialStatus}` : '';
lines.push(`- **Question:** ${node.question}\n - **Node ID:** \`${node.nodeId}\`${taskInfo}${priorityInfo}${assigneeInfo}${statusInfo}\n - **Initial Search Queries:** ${searchQueries}` // Add search queries and task details
);
});
}
else {
lines.push('\nNo sub-topics were specified or created.');
}
return lines.join("\n"); // Combine all lines into the final Markdown string
}
};
// Use the utility function `createFormattedResponse` with the raw data
// and the *contextual* formatter defined above.
// The `isError` flag is automatically inferred from `rawData.success`.
return createFormattedResponse(rawData, contextualFormatter);
}