update_project
Modify a project's knowledge graph data or structure diagram using its unique slug to update information and visual representations.
Instructions
Updates a project's knowledge graph data and/or its structure diagram (in Mermaid.js format). The project is identified by its unique 'slug'. At least one of 'project_knowledge' or 'project_diagram' must be provided for an update to occur.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | ||
| project_knowledge | No | ||
| project_diagram | No |
Implementation Reference
- src/tools/update-project.ts:240-309 (handler)Core handler function that executes the tool logic: validates input, calls SecureApiClient.put to update project data via /project/slug/{slug}, handles responses and errors.async execute(input: UpdateProjectInput): Promise<unknown> { logger.info('Executing update-project tool', input); try { // Use the injected API client to update project if (!this.apiClient) { throw new Error('API client not available - tool not properly initialized'); } // Extract project slug const { slug, ...updateData } = input; // Update project using the API endpoint const url = `/project/slug/${slug.toUpperCase()}`; logger.debug(`Making PUT request to: ${url}`); const responseData = await this.apiClient.put<UpdateProjectApiResponse>(url, updateData) as unknown as UpdateProjectApiResponse; if (!responseData.success) { const apiErrorMessage = responseData.message || 'API reported update failure without a specific message.'; logger.warn(`Update project API call for ${slug} returned success:false. Message: ${apiErrorMessage}`); return { isError: true, content: [{ type: "text", text: `Update for project ${slug} failed: ${apiErrorMessage}` }] }; } // At this point, responseData.success is true const updatedFieldsList = Object.keys(updateData).join(', ') || 'no specific fields (refresh)'; const apiMessage = responseData.message || 'Project successfully updated.'; if (responseData.project) { const diagramFromResponse = responseData.project.project_diagram; // snake_case access return { slug: responseData.project.slug, name: responseData.project.name, description: responseData.project.description, project_knowledge: responseData.project.project_knowledge || {}, // snake_case access and output project_diagram: diagramFromResponse || '', // Use the new variable (already snake_case) updateConfirmation: `Project ${responseData.project.slug} updated fields: ${updatedFieldsList}. API: ${apiMessage}` }; } else { // responseData.success is true, but responseData.project is missing. logger.warn(`Update project API call for ${slug} succeeded but returned no project data. API message: ${apiMessage}`); return { slug: slug, name: '', description: '', project_knowledge: input.project_knowledge || {}, // Input is snake_case from Zod schema project_diagram: input.project_diagram || '', // Input is snake_case from Zod schema updateConfirmation: `Project ${slug} update reported success by API, but full project details were not returned. Attempted to update fields: ${updatedFieldsList}. API: ${apiMessage}` }; } } catch (error) { let errorMessage = (error instanceof Error) ? error.message : 'An unknown error occurred'; logger.error(`Error in update-project tool: ${errorMessage}`, error instanceof Error ? error : undefined); if (error instanceof Error && (error as any).status === 404) { errorMessage = `Project with slug '${input.slug}' not found.`; } else if (error instanceof Error && error.message.includes('not found')) { // Fallback for other not found indications errorMessage = `Project with slug '${input.slug}' not found or update failed.`; } return { isError: true, content: [{ type: "text", text: errorMessage }] }; } }
- src/tools/update-project.ts:82-107 (schema)Zod schema for update_project tool input validation, including slug (required), project_knowledge and project_diagram (at least one required), with detailed constraints.const UpdateProjectSchema = z.object({ // Required field to identify the project slug: z.string({ required_error: "Project slug is required to identify the project", invalid_type_error: "Project slug must be a string" }) .regex(/^[A-Za-z]{3}$/, { message: "Project slug must be three letters (e.g., CRD or crd). Case insensitive." }) .describe("Project slug to identify the project to update (case insensitive)"), // Optional fields that can be updated with security constraints project_knowledge: ProjectKnowledgeSchema.optional().describe("Project knowledge graph data (structured JSON object with size limits)"), project_diagram: z.string() .max(15000, "Project diagram cannot exceed 15000 characters") .optional() .describe("Project structure diagram (Mermaid.js format)"), }).strict().refine( // Ensure at least one field to update is provided (data) => { const updateFields = ['project_knowledge', 'project_diagram']; return updateFields.some(field => field in data); }, { message: 'At least one field to update must be provided', path: ['updateFields'] } );
- src/index.ts:315-330 (registration)Registration of UpdateProjectTool instance with SecureApiClient in the production MCP server, added to tools array and registered via tool.register(server).const tools: any[] = [ new StartProjectTool(secureApiClient), new GetPromptTool(secureApiClient), new GetTaskTool(secureApiClient), new GetProjectTool(secureApiClient), new UpdateTaskTool(secureApiClient), new UpdateProjectTool(secureApiClient), new ListProjectsTool(secureApiClient), new ListTasksTool(secureApiClient), new NextTaskTool(secureApiClient), ]; // Register each tool with the server tools.forEach(tool => { tool.register(server); });
- src/tools/update-project.ts:17-77 (schema)Supporting schema for project_knowledge field, defining flexible structure for components, dependencies, technologies, architecture, etc., with size limits.const ProjectKnowledgeSchema = z.object({ // Core project information - flexible to support both strings and objects components: z.array( z.union([ z.string().max(500, "Component description too long"), z.object({ name: z.string().max(100, "Component name too long"), type: z.string().max(50, "Component type too long").optional(), status: z.string().max(50, "Component status too long").optional(), description: z.string().max(500, "Component description too long").optional(), }).passthrough() // Allow additional properties ]) ).max(50, "Too many components").optional(), dependencies: z.array( z.union([ z.string().max(500, "Dependency description too long"), z.object({ name: z.string().max(100, "Dependency name too long"), version: z.string().max(50, "Dependency version too long").optional(), purpose: z.string().max(500, "Dependency purpose too long").optional(), }).passthrough() ]) ).max(50, "Too many dependencies").optional(), technologies: z.array( z.union([ z.string().max(500, "Technology description too long"), // Increased from 50 to 500 z.object({ name: z.string().max(100, "Technology name too long"), type: z.string().max(50, "Technology type too long").optional(), purpose: z.string().max(500, "Technology purpose too long").optional(), version: z.string().max(50, "Technology version too long").optional(), }).passthrough() ]) ).max(30, "Too many technologies").optional(), // Increased from 20 to 30 // Architecture and design architecture: z.string().max(3000, "Architecture description too long").optional(), // Increased from 2000 patterns: z.array( z.union([ z.string().max(200, "Pattern description too long"), // Increased from 100 z.object({ name: z.string().max(100, "Pattern name too long"), description: z.string().max(500, "Pattern description too long").optional(), }).passthrough() ]) ).max(30, "Too many patterns").optional(), // Increased from 20 // Documentation and notes notes: z.string().max(10000, "Notes too long").optional(), // Increased from 5000 links: z.array(z.string().url("Invalid URL format").max(500, "URL too long")).max(20, "Too many links").optional(), // Increased from 10 // Custom metadata (controlled) - more flexible metadata: z.record( z.union([ z.string().max(1000, "Metadata value too long"), // Increased from 500 z.object({}).passthrough() // Allow objects in metadata ]) ).optional(), }).passthrough(); // Allow additional properties for maximum flexibility