UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

179 lines (178 loc) • 10.6 kB
import { z } from 'zod'; import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; import logger from '../../logger.js'; import { registerTool } from '../../services/routing/toolRegistry.js'; import { jobManager, JobStatus } from '../../services/job-manager/index.js'; import { createJobStatusMessage } from '../../services/job-manager/jobStatusMessage.js'; const getJobResultInputSchemaShape = { jobId: z.string().uuid({ message: "Invalid Job ID format. Must be a UUID." }).describe("The unique identifier of the job to retrieve."), includeDetails: z.boolean().default(true).optional().describe("Whether to include detailed diagnostic information in the response. Defaults to true.") }; export const getJobResult = async (params, _config, context) => { const { jobId, includeDetails = true } = params; const sessionId = context?.sessionId || 'unknown-session'; const transportType = context?.transportType || 'unknown'; try { logger.info({ jobId, sessionId, transportType }, `Attempting to retrieve result for job.`); const { job, waitTime, shouldWait } = jobManager.getJobWithRateLimit(jobId); if (!job) { logger.warn({ jobId }, `Job not found.`); const notFoundError = new McpError(ErrorCode.InvalidParams, `Job with ID '${jobId}' not found.`); return { content: [{ type: 'text', text: notFoundError.message }], isError: true, errorDetails: notFoundError }; } if (shouldWait) { logger.info({ jobId, waitTime }, `Rate limited job status request.`); const statusMessage = createJobStatusMessage(jobId, job.toolName, job.status, `Rate limited: Please wait ${Math.ceil(waitTime / 1000)} seconds before checking again.`, undefined, job.createdAt, job.updatedAt, includeDetails ? job.details : undefined); return { content: [{ type: 'text', text: `Job '${jobId}' (${job.toolName}) status is being checked too frequently. Please wait ${Math.ceil(waitTime / 1000)} seconds before checking again. Current status: ${job.status}, last updated at: ${new Date(job.updatedAt).toISOString()}.` }], isError: false, pollInterval: waitTime, jobStatus: statusMessage }; } let responseText = ''; let finalResult = undefined; switch (job.status) { case JobStatus.PENDING: responseText = `Job '${jobId}' (${job.toolName}) is pending. Created at: ${new Date(job.createdAt).toISOString()}.`; break; case JobStatus.RUNNING: responseText = `Job '${jobId}' (${job.toolName}) is running. Status updated at: ${new Date(job.updatedAt).toISOString()}.`; if (job.progressMessage) { responseText += `\n\nšŸ“Š **Progress**: ${job.progressMessage}`; } if (job.progressPercentage !== undefined) { responseText += `\nā±ļø **Completion**: ${job.progressPercentage}%`; } if (job.details?.metadata?.estimatedCompletion && (typeof job.details.metadata.estimatedCompletion === 'string' || typeof job.details.metadata.estimatedCompletion === 'number' || job.details.metadata.estimatedCompletion instanceof Date)) { responseText += `\nšŸ•’ **Estimated Completion**: ${new Date(job.details.metadata.estimatedCompletion).toISOString()}`; } responseText += `\n\nšŸ’” **Tip**: Continue polling for updates. This job will provide detailed results when complete.`; break; case JobStatus.COMPLETED: responseText = `Job '${jobId}' (${job.toolName}) completed successfully at: ${new Date(job.updatedAt).toISOString()}.`; if (job.result) { finalResult = JSON.parse(JSON.stringify(job.result)); if (finalResult) { if (finalResult.taskData && Array.isArray(finalResult.taskData) && finalResult.taskData.length > 0) { const taskSummary = `\n\nšŸ“Š **Task Summary:**\n` + `• Total Tasks: ${finalResult.taskData.length}\n` + `• Total Hours: ${finalResult.taskData.reduce((sum, task) => sum + (typeof task.estimatedHours === 'number' ? task.estimatedHours : 0), 0)}h\n` + `• Files Created: ${Array.isArray(finalResult.fileReferences) ? finalResult.fileReferences.length : 0}\n`; const completionNote = { type: 'text', text: taskSummary + `\n---\nJob Status: COMPLETED (${new Date(job.updatedAt).toISOString()})` }; finalResult.content = [...(finalResult.content || []), completionNote]; } else { const completionNote = { type: 'text', text: `\n---\nJob Status: COMPLETED (${new Date(job.updatedAt).toISOString()})` }; finalResult.content = [...(finalResult.content || []), completionNote]; } } else { logger.error({ jobId }, "Deep copy of job result failed unexpectedly for COMPLETED job."); responseText += ' Failed to process final result.'; } } else { responseText += ' However, the final result is missing.'; logger.error({ jobId }, "Job status is COMPLETED but result is missing."); } break; case JobStatus.FAILED: responseText = `Job '${jobId}' (${job.toolName}) failed at: ${new Date(job.updatedAt).toISOString()}. Reason: ${job.progressMessage || 'No failure message available.'}`; if (job.result && job.result.isError) { finalResult = JSON.parse(JSON.stringify(job.result)); if (finalResult) { const failureNote = { type: 'text', text: `\n---\nJob Status: FAILED (${new Date(job.updatedAt).toISOString()})` }; finalResult.content = [...(finalResult.content || []), failureNote]; } else { logger.error({ jobId }, "Deep copy of job result failed unexpectedly for FAILED job."); responseText += ' Failed to process error result.'; } } else { responseText += ' Error details are missing.'; logger.error({ jobId }, "Job status is FAILED but error result is missing or not marked as error."); finalResult = { content: [{ type: 'text', text: responseText }], isError: true, errorDetails: new McpError(ErrorCode.InternalError, "Job failed but error details are missing.", { jobId }) }; } break; default: logger.error({ jobId, status: job.status }, `Job has unknown status.`); responseText = `Job '${jobId}' has an unknown status: ${job.status}.`; break; } if (finalResult) { logger.info({ jobId, status: job.status }, `Returning final stored result for job.`); return finalResult; } const statusMessage = createJobStatusMessage(jobId, job.toolName, job.status, job.progressMessage, job.progressPercentage, job.createdAt, job.updatedAt, includeDetails ? job.details : undefined); if (statusMessage.pollingRecommendation) { responseText += `\n\nRecommended polling interval: ${statusMessage.pollingRecommendation.interval / 1000} seconds.`; } if (includeDetails && statusMessage.details) { responseText += '\n\n--- Detailed Information ---'; if (statusMessage.details.currentStage) { responseText += `\nCurrent Stage: ${statusMessage.details.currentStage}`; } if (statusMessage.details.subProgress !== undefined) { responseText += `\nSub-progress: ${statusMessage.details.subProgress}%`; } if (statusMessage.details.diagnostics && statusMessage.details.diagnostics.length > 0) { responseText += '\nDiagnostics:'; statusMessage.details.diagnostics.forEach((diagnostic, index) => { responseText += `\n ${index + 1}. ${diagnostic}`; }); } if (statusMessage.details.metadata && Object.keys(statusMessage.details.metadata).length > 0) { responseText += '\nMetadata:'; Object.entries(statusMessage.details.metadata).forEach(([key, value]) => { responseText += `\n ${key}: ${JSON.stringify(value)}`; }); } } logger.info({ jobId, status: job.status }, `Returning current status for job.`); return { content: [{ type: "text", text: responseText }], isError: false, jobStatus: statusMessage, pollingRecommendation: statusMessage.pollingRecommendation }; } catch (error) { logger.error({ err: error, jobId }, 'Error retrieving job result.'); const execError = new McpError(ErrorCode.InternalError, `An unexpected error occurred while retrieving job '${jobId}'.`, { originalError: String(error) }); return { content: [{ type: 'text', text: execError.message }], isError: true, errorDetails: execError }; } }; const getJobResultToolDefinition = { name: "get-job-result", description: "Retrieves the current status and, if available, the final result of a background job. Supports enhanced diagnostic information for debugging and troubleshooting.", inputSchema: getJobResultInputSchemaShape, executor: getJobResult }; registerTool(getJobResultToolDefinition); logger.info("Registered tool: get-job-result");