orchestry-mcp
Version:
Orchestry MCP Server for multi-session task management
483 lines (428 loc) • 14.5 kB
text/typescript
import { Server as SocketIOServer } from 'socket.io';
import { DatabaseManager } from '../database-manager.js';
import { Database } from '../database.js';
import { z } from 'zod';
import type {
Project,
Workspace,
Goal,
Task,
Document,
TaskStatus,
Priority,
Session,
ProjectStats,
} from '../../shared/types.js';
export class OrchestryTools {
private currentProjectId: string | null = null;
private currentDb: Database | null = null;
constructor(
private dbManager: DatabaseManager,
private io: SocketIOServer
) {}
private async getCurrentDatabase(): Promise<Database> {
if (!this.currentProjectId) {
// Get the most recent project or create a default one
const currentProject = this.dbManager.getCurrentProject();
if (currentProject) {
this.currentProjectId = currentProject;
} else {
// Create a default project
this.currentProjectId = await this.dbManager.createProject(
'Default Project',
'Default project for initial tasks'
);
}
}
if (!this.currentDb) {
this.currentDb = await this.dbManager.getProjectDatabase(this.currentProjectId);
}
return this.currentDb;
}
private async switchToProject(projectId: string): Promise<Database> {
this.currentProjectId = projectId;
this.currentDb = await this.dbManager.switchProject(projectId);
return this.currentDb;
}
getToolDefinitions() {
return [
{
name: 'create_project',
description: `Create a new isolated project with its own database.
Each project has completely separate data from other projects.
Example: create_project("E-commerce Platform", "Build a modern e-commerce platform")`,
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Project name (will be used to generate project ID)' },
description: { type: 'string', description: 'Project description' },
},
required: ['name', 'description'],
},
},
{
name: 'list_all_projects',
description: `List all available projects across the system.
Shows project metadata including when they were last accessed.
Example: list_all_projects()`,
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'switch_project',
description: `Switch to a different project database.
All subsequent operations will work on the selected project.
Example: switch_project("e-commerce-platform")`,
inputSchema: {
type: 'object',
properties: {
projectId: { type: 'string', description: 'Project ID to switch to' },
},
required: ['projectId'],
},
},
{
name: 'get_current_project',
description: `Get the currently active project.
Example: get_current_project()`,
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'archive_project',
description: `Archive a project (soft delete - can be restored).
Example: archive_project("old-project")`,
inputSchema: {
type: 'object',
properties: {
projectId: { type: 'string', description: 'Project ID to archive' },
},
required: ['projectId'],
},
},
{
name: 'list_workspaces',
description: `List all workspaces in the current project.
Example: list_workspaces()`,
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'create_workspace',
description: `Create a new workspace in the current project.
Example: create_workspace("Frontend Development", "React UI components and pages")`,
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Workspace name' },
description: { type: 'string', description: 'Workspace description' },
},
required: ['name'],
},
},
{
name: 'create_goal',
description: `Create a new goal within a workspace.
Example: create_goal("workspace-id", "Implement authentication", "User login and registration system")`,
inputSchema: {
type: 'object',
properties: {
workspaceId: { type: 'string', description: 'Workspace ID' },
title: { type: 'string', description: 'Goal title' },
description: { type: 'string', description: 'Goal description' },
},
required: ['workspaceId', 'title'],
},
},
{
name: 'create_task',
description: `Create a new task within a goal.
Example: create_task("goal-id", "Design login form", "Create responsive login form with validation", "high")`,
inputSchema: {
type: 'object',
properties: {
goalId: { type: 'string', description: 'Goal ID' },
title: { type: 'string', description: 'Task title' },
description: { type: 'string', description: 'Task description' },
priority: {
type: 'string',
enum: ['low', 'medium', 'high', 'critical'],
description: 'Task priority'
},
assigneeId: { type: 'string', description: 'Optional assignee ID' },
},
required: ['goalId', 'title'],
},
},
{
name: 'update_task_status',
description: `Update the status of a task.
Example: update_task_status("task-id", "in_progress")`,
inputSchema: {
type: 'object',
properties: {
taskId: { type: 'string', description: 'Task ID' },
status: {
type: 'string',
enum: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'],
description: 'New task status',
},
},
required: ['taskId', 'status'],
},
},
{
name: 'get_project_overview',
description: `Get a comprehensive overview of the current project including all workspaces, goals, and tasks.
Example: get_project_overview()`,
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'get_project_stats',
description: `Get statistics about the current project.
Example: get_project_stats()`,
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'search_tasks',
description: `Search for tasks across the current project.
Example: search_tasks("authentication")`,
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
status: {
type: 'string',
enum: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'],
description: 'Filter by status',
},
priority: {
type: 'string',
enum: ['low', 'medium', 'high', 'critical'],
description: 'Filter by priority',
},
},
required: ['query'],
},
},
{
name: 'create_session',
description: `Create a new session for multi-agent collaboration.
Example: create_session("Claude Agent 1", "Frontend development session")`,
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Session name/identifier' },
description: { type: 'string', description: 'Session description' },
},
required: ['name'],
},
},
{
name: 'get_active_sessions',
description: `Get all currently active sessions in the current project.
Example: get_active_sessions()`,
inputSchema: {
type: 'object',
properties: {},
},
},
];
}
async executeTool(name: string, args: any) {
try {
// Project management tools (don't need current database)
if (name === 'create_project') {
const projectId = await this.dbManager.createProject(args.name, args.description);
await this.switchToProject(projectId);
return {
success: true,
projectId,
message: `Created and switched to project: ${args.name}`,
};
}
if (name === 'list_all_projects') {
const projects = this.dbManager.listProjects();
return {
success: true,
projects,
currentProject: this.currentProjectId,
};
}
if (name === 'switch_project') {
await this.switchToProject(args.projectId);
return {
success: true,
message: `Switched to project: ${args.projectId}`,
projectId: args.projectId,
};
}
if (name === 'get_current_project') {
if (!this.currentProjectId) {
return {
success: false,
message: 'No project currently selected',
};
}
const projects = this.dbManager.listProjects();
const currentProject = projects.find(p => p.id === this.currentProjectId);
return {
success: true,
project: currentProject,
projectId: this.currentProjectId,
};
}
if (name === 'archive_project') {
this.dbManager.archiveProject(args.projectId);
if (this.currentProjectId === args.projectId) {
this.currentProjectId = null;
this.currentDb = null;
}
return {
success: true,
message: `Archived project: ${args.projectId}`,
};
}
// All other tools need the current database
const db = await this.getCurrentDatabase();
switch (name) {
case 'list_workspaces': {
const project = await db.getProjectWithDetails(await this.getProjectIdFromDb(db));
return {
success: true,
workspaces: project?.workspaces || [],
projectId: this.currentProjectId,
};
}
case 'create_workspace': {
const projectId = await this.getProjectIdFromDb(db);
const workspace = await db.createWorkspace({
projectId,
name: args.name,
description: args.description || '',
});
this.io.emit('workspace:created', workspace);
return {
success: true,
workspace,
message: `Created workspace: ${args.name}`,
};
}
case 'create_goal': {
const goal = await db.createGoal({
workspaceId: args.workspaceId,
title: args.title,
description: args.description || '',
});
this.io.emit('goal:created', goal);
return {
success: true,
goal,
message: `Created goal: ${args.title}`,
};
}
case 'create_task': {
const task = await db.createTask({
goalId: args.goalId,
title: args.title,
description: args.description || '',
priority: args.priority || 'medium',
});
this.io.emit('task:created', task);
return {
success: true,
task,
message: `Created task: ${args.title}`,
};
}
case 'update_task_status': {
const task = await db.updateTaskStatus(args.taskId, args.status);
this.io.emit('task:updated', task);
return {
success: true,
task,
message: `Updated task status to: ${args.status}`,
};
}
case 'get_project_overview': {
const projectId = await this.getProjectIdFromDb(db);
const project = await db.getProjectWithDetails(projectId);
return {
success: true,
project,
currentProjectId: this.currentProjectId,
};
}
case 'get_project_stats': {
const projectId = await this.getProjectIdFromDb(db);
const stats = await db.getProjectStats(projectId);
return {
success: true,
stats,
projectId: this.currentProjectId,
};
}
case 'search_tasks': {
const tasks = await db.searchTasks(args.query, {
status: args.status,
priority: args.priority,
});
return {
success: true,
tasks,
count: tasks.length,
};
}
case 'create_session': {
const projectId = await this.getProjectIdFromDb(db);
const session = await db.createSession({
projectId,
name: args.name,
});
return {
success: true,
session,
message: `Created session: ${args.name}`,
};
}
case 'get_active_sessions': {
const projectId = await this.getProjectIdFromDb(db);
const sessions = await db.getActiveSessions(projectId);
return {
success: true,
sessions,
count: sessions.length,
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
console.error(`Error executing tool ${name}:`, error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
private async getProjectIdFromDb(db: Database): Promise<string> {
// Get the first (and should be only) project from the database
const projects = await db.getAllProjects();
if (projects.length === 0) {
throw new Error('No project found in database');
}
return projects[0].id;
}
}