@pimzino/agentic-tools-mcp
Version:
A comprehensive MCP server for task management and agent memories with JSON file storage
169 lines (168 loc) • 5.79 kB
JavaScript
import { promises as fs } from 'fs';
import { join } from 'path';
/**
* File-based storage implementation using JSON with project-specific directories
*/
export class FileStorage {
workingDirectory;
storageDir;
dataFile;
data;
constructor(workingDirectory) {
this.workingDirectory = workingDirectory;
this.storageDir = join(workingDirectory, '.agentic-tools-mcp', 'tasks');
this.dataFile = join(this.storageDir, 'tasks.json');
this.data = {
projects: [],
tasks: [],
subtasks: []
};
}
/**
* Initialize storage by validating working directory and loading data from file
*/
async initialize() {
try {
// Validate that working directory exists
await fs.access(this.workingDirectory);
}
catch (error) {
throw new Error(`Working directory does not exist or is not accessible: ${this.workingDirectory}`);
}
try {
// Ensure .agentic-tools-mcp/tasks directory exists
await fs.mkdir(this.storageDir, { recursive: true });
// Try to load existing data
const fileContent = await fs.readFile(this.dataFile, 'utf-8');
this.data = JSON.parse(fileContent);
}
catch (error) {
// File doesn't exist or is invalid, start with empty data
await this.save();
}
}
/**
* Save data to file
*/
async save() {
await fs.writeFile(this.dataFile, JSON.stringify(this.data, null, 2));
}
// Project operations
async getProjects() {
return [...this.data.projects];
}
async getProject(id) {
return this.data.projects.find(p => p.id === id) || null;
}
async createProject(project) {
this.data.projects.push(project);
await this.save();
return project;
}
async updateProject(id, updates) {
const index = this.data.projects.findIndex(p => p.id === id);
if (index === -1)
return null;
this.data.projects[index] = { ...this.data.projects[index], ...updates };
await this.save();
return this.data.projects[index];
}
async deleteProject(id) {
const index = this.data.projects.findIndex(p => p.id === id);
if (index === -1)
return false;
this.data.projects.splice(index, 1);
// Also delete all related tasks and subtasks
await this.deleteTasksByProject(id);
await this.deleteSubtasksByProject(id);
await this.save();
return true;
}
// Task operations
async getTasks(projectId) {
if (projectId) {
return this.data.tasks.filter(t => t.projectId === projectId);
}
return [...this.data.tasks];
}
async getTask(id) {
return this.data.tasks.find(t => t.id === id) || null;
}
async createTask(task) {
this.data.tasks.push(task);
await this.save();
return task;
}
async updateTask(id, updates) {
const index = this.data.tasks.findIndex(t => t.id === id);
if (index === -1)
return null;
this.data.tasks[index] = { ...this.data.tasks[index], ...updates };
await this.save();
return this.data.tasks[index];
}
async deleteTask(id) {
const index = this.data.tasks.findIndex(t => t.id === id);
if (index === -1)
return false;
this.data.tasks.splice(index, 1);
// Also delete all related subtasks
await this.deleteSubtasksByTask(id);
await this.save();
return true;
}
async deleteTasksByProject(projectId) {
const tasksToDelete = this.data.tasks.filter(t => t.projectId === projectId);
this.data.tasks = this.data.tasks.filter(t => t.projectId !== projectId);
// Delete subtasks for each deleted task
for (const task of tasksToDelete) {
await this.deleteSubtasksByTask(task.id);
}
return tasksToDelete.length;
}
// Subtask operations
async getSubtasks(taskId, projectId) {
let subtasks = [...this.data.subtasks];
if (taskId) {
subtasks = subtasks.filter(s => s.taskId === taskId);
}
if (projectId) {
subtasks = subtasks.filter(s => s.projectId === projectId);
}
return subtasks;
}
async getSubtask(id) {
return this.data.subtasks.find(s => s.id === id) || null;
}
async createSubtask(subtask) {
this.data.subtasks.push(subtask);
await this.save();
return subtask;
}
async updateSubtask(id, updates) {
const index = this.data.subtasks.findIndex(s => s.id === id);
if (index === -1)
return null;
this.data.subtasks[index] = { ...this.data.subtasks[index], ...updates };
await this.save();
return this.data.subtasks[index];
}
async deleteSubtask(id) {
const index = this.data.subtasks.findIndex(s => s.id === id);
if (index === -1)
return false;
this.data.subtasks.splice(index, 1);
await this.save();
return true;
}
async deleteSubtasksByTask(taskId) {
const subtasksToDelete = this.data.subtasks.filter(s => s.taskId === taskId);
this.data.subtasks = this.data.subtasks.filter(s => s.taskId !== taskId);
return subtasksToDelete.length;
}
async deleteSubtasksByProject(projectId) {
const subtasksToDelete = this.data.subtasks.filter(s => s.projectId === projectId);
this.data.subtasks = this.data.subtasks.filter(s => s.projectId !== projectId);
return subtasksToDelete.length;
}
}