UNPKG

@tosin2013/mcp-shrimp-task-manager

Version:

Enhanced MCP Shrimp Task Manager with comprehensive LLM integration. A task management tool built for AI Agents, emphasizing chain-of-thought, reflection, and style consistency. Features real GPT-4 ↔ MCP tools communication, comprehensive testing pipeline

239 lines 10.4 kB
import { z } from "zod"; import fs from 'fs/promises'; import path from 'path'; // Schema for the get_spec tool export const getSpecSchema = z.object({ specId: z.string().describe("The UUID of the specification to retrieve"), format: z.enum(["markdown", "json", "summary"]).optional().default("markdown").describe("Output format: markdown (full content), json (structured data), or summary (brief overview)") }); /** * Retrieves and returns a stored specification document * * This tool allows users to access complete specification documents that were * created using the create_spec tool and stored in the MCP server's data directory. * * @param params - Parameters containing the specification ID and format preference * @returns The specification content in the requested format */ export async function getSpec(params) { try { const { specId, format } = params; // Validate UUID format const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (!uuidRegex.test(specId)) { return { content: [ { type: "text", text: `# Invalid Specification ID\n\n` + `The provided ID "${specId}" is not a valid UUID format.\n\n` + `**Expected Format**: \`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\`\n\n` + `**Usage Example**:\n` + `\`\`\`\n` + `get_spec({\n` + ` specId: "32b80802-89fb-4b57-bb5b-757561c27a05",\n` + ` format: "markdown" // optional: "markdown", "json", or "summary"\n` + `})\n` + `\`\`\`\n\n` + `To list available specifications, use \`interact_spec\` with command "list".` } ] }; } // Construct the file path const dataDir = path.join(process.cwd(), 'data', 'specifications'); const specPath = path.join(dataDir, `${specId}.md`); try { // Check if the specification file exists await fs.access(specPath); } catch (error) { return { content: [ { type: "text", text: `# Specification Not Found\n\n` + `No specification found with ID: \`${specId}\`\n\n` + `**Possible Causes:**\n` + `- The specification was created in a different session\n` + `- The ID was mistyped or incomplete\n` + `- The specification file was moved or deleted\n\n` + `**Troubleshooting:**\n` + `1. Use \`interact_spec\` with command "list" to see available specifications\n` + `2. Check if you copied the complete UUID from \`create_spec\` output\n` + `3. Verify the specification exists in the MCP server's data directory\n\n` + `**Storage Location**: \`${dataDir}\`` } ] }; } // Read the specification content const specContent = await fs.readFile(specPath, 'utf-8'); if (format === "markdown") { // Return the full markdown content return { content: [ { type: "text", text: `# Retrieved Specification: ${specId}\n\n` + `**Source**: MCP Server Data Directory\n` + `**Format**: Complete Markdown Document\n` + `**Size**: ${specContent.length} characters\n\n` + `---\n\n` + `${specContent}` } ] }; } else if (format === "summary") { // Extract and return a summary const lines = specContent.split('\n'); const title = lines.find(line => line.startsWith('# '))?.substring(2) || 'Unknown Title'; const metadata = extractMetadata(specContent); const overview = extractSection(specContent, 'Overview') || 'No overview available'; return { content: [ { type: "text", text: `# Specification Summary\n\n` + `**Title**: ${title}\n` + `**ID**: ${specId}\n` + `**Status**: ${metadata.status || 'Unknown'}\n` + `**Created**: ${metadata.created || 'Unknown'}\n` + `**Version**: ${metadata.version || 'Unknown'}\n\n` + `## Overview\n\n${overview}\n\n` + `## Sections Available\n\n${extractSectionList(specContent)}\n\n` + `**To view complete specification**: Use \`get_spec\` with format "markdown"\n` + `**To interact with specification**: Use \`interact_spec\` with ID ${specId}` } ] }; } else if (format === "json") { // Parse and return structured data const metadata = extractMetadata(specContent); const sections = extractAllSections(specContent); const structuredData = { id: specId, title: extractTitle(specContent), metadata, sections, storage: { location: specPath, size: specContent.length, retrieved: new Date().toISOString() } }; return { content: [ { type: "text", text: `# Specification Data (JSON Format)\n\n` + `\`\`\`json\n${JSON.stringify(structuredData, null, 2)}\n\`\`\`\n\n` + `**Note**: This is the parsed structure of the specification.\n` + `For the complete formatted document, use format "markdown".` } ] }; } else { // Default fallback case return { content: [ { type: "text", text: `# Invalid Format\n\n` + `The format "${format}" is not supported.\n\n` + `**Supported formats**: markdown, json, summary\n\n` + `Please use one of the supported formats.` } ] }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; return { content: [ { type: "text", text: `# Error Retrieving Specification\n\n` + `An error occurred while retrieving the specification:\n\n` + `**Error**: ${errorMessage}\n\n` + `**Troubleshooting Steps**:\n` + `1. Verify the specification ID is correct\n` + `2. Check that the MCP server has read access to the data directory\n` + `3. Ensure the specification was created successfully\n` + `4. Try using \`interact_spec\` as an alternative access method` } ] }; } } /** * Helper function to extract metadata from markdown content */ function extractMetadata(content) { const metadata = {}; const metadataSection = extractSection(content, 'Specification Metadata'); if (metadataSection) { const lines = metadataSection.split('\n'); for (const line of lines) { const match = line.match(/^- \*\*([^*]+)\*\*:\s*(.+)$/); if (match) { metadata[match[1].toLowerCase()] = match[2].replace(/`/g, ''); } } } return metadata; } /** * Helper function to extract a specific section from markdown content */ function extractSection(content, sectionTitle) { const sectionRegex = new RegExp(`## ${sectionTitle}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`, 'i'); const match = content.match(sectionRegex); return match ? match[1].trim() : null; } /** * Helper function to extract the title from markdown content */ function extractTitle(content) { const match = content.match(/^# (.+)$/m); return match ? match[1] : 'Unknown Title'; } /** * Helper function to extract a list of all sections */ function extractSectionList(content) { const sections = content.match(/^## (.+)$/gm); if (!sections) return 'No sections found'; return sections.map(section => `- ${section.substring(3)}`).join('\n'); } /** * Helper function to extract all sections with their content */ function extractAllSections(content) { const sections = []; const sectionMatches = content.match(/^## (.+)$/gm); if (sectionMatches) { for (let i = 0; i < sectionMatches.length; i++) { const title = sectionMatches[i].substring(3); const nextSection = sectionMatches[i + 1]; let sectionContent; if (nextSection) { const currentIndex = content.indexOf(sectionMatches[i]); const nextIndex = content.indexOf(nextSection); sectionContent = content.substring(currentIndex + sectionMatches[i].length, nextIndex).trim(); } else { const currentIndex = content.indexOf(sectionMatches[i]); sectionContent = content.substring(currentIndex + sectionMatches[i].length).trim(); } sections.push({ title, content: sectionContent }); } } return sections; } //# sourceMappingURL=get-spec.js.map