UNPKG

@codervisor/devlog-mcp

Version:

MCP server for managing development logs and working notes

146 lines (145 loc) 5.21 kB
/** * MCP Tool validation schemas * * This module defines Zod schemas for validating MCP tool arguments. * It reuses business logic schemas from @codervisor/devlog-core and adds * MCP-specific validation layers. */ import { z } from 'zod'; import { DevlogIdSchema, } from '@codervisor/devlog-core'; /** * Devlog tool argument schemas */ export const CreateDevlogArgsSchema = z .object({ title: z.string().min(1, 'Title is required').max(200, 'Title too long'), type: z.enum(['feature', 'bugfix', 'task', 'refactor', 'docs']), description: z.string().min(1, 'Description is required'), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), businessContext: z.string().optional(), technicalContext: z.string().optional(), acceptanceCriteria: z.array(z.string()).optional(), }) .transform((data) => ({ ...data, priority: data.priority ?? 'medium', })); export const UpdateDevlogArgsSchema = z.object({ id: DevlogIdSchema, status: z .enum(['new', 'in-progress', 'blocked', 'in-review', 'testing', 'done', 'cancelled']) .optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), businessContext: z.string().optional(), technicalContext: z.string().optional(), acceptanceCriteria: z.array(z.string()).optional(), }); export const GetDevlogArgsSchema = z.object({ id: DevlogIdSchema, }); export const ListDevlogsArgsSchema = z.object({ status: z .enum(['new', 'in-progress', 'blocked', 'in-review', 'testing', 'done', 'cancelled']) .optional(), type: z.enum(['feature', 'bugfix', 'task', 'refactor', 'docs']).optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), archived: z.boolean().optional(), page: z.number().int().min(1).optional(), limit: z.number().int().min(1).max(100).optional(), sortBy: z.enum(['createdAt', 'updatedAt', 'priority', 'status', 'title']).optional(), sortOrder: z.enum(['asc', 'desc']).optional(), }); export const SearchDevlogsArgsSchema = z.object({ query: z.string().min(1, 'Search query is required'), status: z .enum(['new', 'in-progress', 'blocked', 'in-review', 'testing', 'done', 'cancelled']) .optional(), type: z.enum(['feature', 'bugfix', 'task', 'refactor', 'docs']).optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), archived: z.boolean().optional(), }); export const AddDevlogNoteArgsSchema = z .object({ id: DevlogIdSchema, note: z.string().min(1, 'Note content is required'), category: z.enum(['progress', 'issue', 'solution', 'idea', 'reminder', 'feedback']).optional(), files: z.array(z.string()).optional(), codeChanges: z.string().optional(), }) .transform((data) => ({ ...data, category: data.category ?? 'progress', })); export const UpdateDevlogWithNoteArgsSchema = z .object({ id: DevlogIdSchema, status: z .enum(['new', 'in-progress', 'blocked', 'in-review', 'testing', 'done', 'cancelled']) .optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), note: z.string().min(1, 'Note content is required'), category: z.enum(['progress', 'issue', 'solution', 'idea', 'reminder', 'feedback']).optional(), files: z.array(z.string()).optional(), codeChanges: z.string().optional(), }) .transform((data) => ({ ...data, category: data.category ?? 'progress', })); export const CompleteDevlogArgsSchema = z.object({ id: DevlogIdSchema, summary: z.string().optional(), }); export const CloseDevlogArgsSchema = z.object({ id: DevlogIdSchema, reason: z.string().optional(), }); export const ArchiveDevlogArgsSchema = z.object({ id: DevlogIdSchema, }); export const DiscoverRelatedDevlogsArgsSchema = z.object({ workDescription: z.string().min(1, 'Work description is required'), workType: z.enum(['feature', 'bugfix', 'task', 'refactor', 'docs']), keywords: z.array(z.string()).optional(), scope: z.string().optional(), }); /** * Project tool argument schemas */ export const ListProjectsArgsSchema = z.object({ // No arguments for list projects }); export const GetCurrentProjectArgsSchema = z.object({ // No arguments for get current project }); export const SwitchProjectArgsSchema = z.object({ projectId: z.string().regex(/^\d+$/, 'Project ID must be a number'), }); /** * Validation helper functions */ export class McpToolValidator { /** * Validate tool arguments against schema */ static validate(schema, data) { const result = schema.safeParse(data); if (result.success) { return { success: true, data: result.data }; } return { success: false, errors: result.error.errors.map((err) => `${err.path.join('.')}: ${err.message}`), }; } /** * Validate and throw on error */ static validateOrThrow(schema, data) { const result = this.validate(schema, data); if (!result.success) { throw new Error(`Validation failed: ${result.errors.join(', ')}`); } return result.data; } }