/**
* List Projects Tool
*
* Lists all projects in the user workspace from the CodeRide API
*/
import { z } from 'zod';
import { BaseTool, MCPToolDefinition, ToolAnnotations, AgentInstructions } from '../utils/base-tool.js';
import { SecureApiClient, ProjectListApiResponse } from '../utils/secure-api-client.js';
import { logger } from '../utils/logger.js';
/**
* Schema for the list-projects tool input
* No input parameters required - workspace is extracted from API key
*/
const ListProjectsSchema = z.object({}).strict();
/**
* Type for the list-projects tool input
*/
type ListProjectsInput = z.infer<typeof ListProjectsSchema>;
/**
* List Projects Tool Implementation
*/
export class ListProjectsTool extends BaseTool<typeof ListProjectsSchema> {
readonly name = 'list_projects';
readonly description = "Lists all projects in the user workspace. No input parameters required as the workspace is automatically determined from the API key authentication.";
readonly zodSchema = ListProjectsSchema;
readonly annotations: ToolAnnotations = {
title: "List Projects",
readOnlyHint: true,
openWorldHint: true, // Interacts with an external API
};
/**
* Constructor with dependency injection
*/
constructor(apiClient?: SecureApiClient) {
super(apiClient);
}
/**
* Returns the full tool definition conforming to MCP.
*/
getMCPToolDefinition(): MCPToolDefinition {
return {
name: this.name,
description: this.description,
annotations: this.annotations,
inputSchema: {
type: "object",
properties: {},
required: [],
additionalProperties: false
}
};
}
/**
* Generate agent instructions for list_projects tool
*/
protected generateAgentInstructions(input: ListProjectsInput, result: any): AgentInstructions {
return {
immediateActions: [
"Review available projects and their descriptions",
"Help user select appropriate project for their work",
"Consider project scope and current status for selection"
],
nextRecommendedTools: ["start_project", "get_project"],
workflowPhase: 'discovery',
criticalReminders: [
"Use start_project for new project initialization",
"Use get_project to understand existing project context"
],
automationHints: {
projectSelection: "Guide user to select projects based on their current objectives",
workflowGuidance: {
newProject: "Use start_project for project initialization",
existingProject: "Use get_project to establish project context"
}
}
};
}
/**
* Execute the list-projects tool
*/
async execute(input: ListProjectsInput): Promise<unknown> {
logger.info('Executing list-projects tool', input);
try {
// Use the injected API client to get project list
if (!this.apiClient) {
throw new Error('API client not available - tool not properly initialized');
}
const url = `/project/list`;
logger.debug(`Making GET request to: ${url}`);
const responseData = await this.apiClient.get<ProjectListApiResponse[]>(url) as unknown as ProjectListApiResponse[];
if (!responseData || !Array.isArray(responseData)) {
logger.warn(`No projects found or invalid response format from ${url}`);
return { projects: [] };
}
// Return formatted project list
return {
projects: responseData.map(project => ({
id: project.id,
name: project.name,
description: project.description,
slug: project.slug,
// status: project.status || 'draft', // Fallback for projects without status
workspace: {
id: project.workspace?.id || '',
name: project.workspace?.name || ''
}
})),
totalCount: responseData.length
};
} catch (error) {
const errorMessage = (error instanceof Error) ? error.message : 'An unknown error occurred';
logger.error(`Error in project-list tool: ${errorMessage}`, error instanceof Error ? error : undefined);
return {
isError: true,
content: [{ type: "text", text: errorMessage }]
};
}
}
}