This is page 32 of 33. Use http://codebase.md/tosin2013/documcp?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .dockerignore
├── .eslintignore
├── .eslintrc.json
├── .github
│ ├── agents
│ │ ├── documcp-ast.md
│ │ ├── documcp-deploy.md
│ │ ├── documcp-memory.md
│ │ ├── documcp-test.md
│ │ └── documcp-tool.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ ├── ISSUE_TEMPLATE
│ │ ├── automated-changelog.md
│ │ ├── bug_report.md
│ │ ├── bug_report.yml
│ │ ├── documentation_issue.md
│ │ ├── feature_request.md
│ │ ├── feature_request.yml
│ │ ├── npm-publishing-fix.md
│ │ └── release_improvements.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── release-drafter.yml
│ └── workflows
│ ├── auto-merge.yml
│ ├── ci.yml
│ ├── codeql.yml
│ ├── dependency-review.yml
│ ├── deploy-docs.yml
│ ├── README.md
│ ├── release-drafter.yml
│ └── release.yml
├── .gitignore
├── .husky
│ ├── commit-msg
│ └── pre-commit
├── .linkcheck.config.json
├── .markdown-link-check.json
├── .nvmrc
├── .pre-commit-config.yaml
├── .versionrc.json
├── ARCHITECTURAL_CHANGES_SUMMARY.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── commitlint.config.js
├── CONTRIBUTING.md
├── docker-compose.docs.yml
├── Dockerfile.docs
├── docs
│ ├── .docusaurus
│ │ ├── docusaurus-plugin-content-docs
│ │ │ └── default
│ │ │ └── __mdx-loader-dependency.json
│ │ └── docusaurus-plugin-content-pages
│ │ └── default
│ │ └── __plugin.json
│ ├── adrs
│ │ ├── adr-0001-mcp-server-architecture.md
│ │ ├── adr-0002-repository-analysis-engine.md
│ │ ├── adr-0003-static-site-generator-recommendation-engine.md
│ │ ├── adr-0004-diataxis-framework-integration.md
│ │ ├── adr-0005-github-pages-deployment-automation.md
│ │ ├── adr-0006-mcp-tools-api-design.md
│ │ ├── adr-0007-mcp-prompts-and-resources-integration.md
│ │ ├── adr-0008-intelligent-content-population-engine.md
│ │ ├── adr-0009-content-accuracy-validation-framework.md
│ │ ├── adr-0010-mcp-resource-pattern-redesign.md
│ │ ├── adr-0011-ce-mcp-compatibility.md
│ │ ├── adr-0012-priority-scoring-system-for-documentation-drift.md
│ │ ├── adr-0013-release-pipeline-and-package-distribution.md
│ │ └── README.md
│ ├── api
│ │ ├── .nojekyll
│ │ ├── assets
│ │ │ ├── hierarchy.js
│ │ │ ├── highlight.css
│ │ │ ├── icons.js
│ │ │ ├── icons.svg
│ │ │ ├── main.js
│ │ │ ├── navigation.js
│ │ │ ├── search.js
│ │ │ └── style.css
│ │ ├── hierarchy.html
│ │ ├── index.html
│ │ ├── modules.html
│ │ └── variables
│ │ └── TOOLS.html
│ ├── assets
│ │ └── logo.svg
│ ├── CE-MCP-FINDINGS.md
│ ├── development
│ │ └── MCP_INSPECTOR_TESTING.md
│ ├── docusaurus.config.js
│ ├── explanation
│ │ ├── architecture.md
│ │ └── index.md
│ ├── guides
│ │ ├── link-validation.md
│ │ ├── playwright-integration.md
│ │ └── playwright-testing-workflow.md
│ ├── how-to
│ │ ├── analytics-setup.md
│ │ ├── change-watcher.md
│ │ ├── custom-domains.md
│ │ ├── documentation-freshness-tracking.md
│ │ ├── drift-priority-scoring.md
│ │ ├── github-pages-deployment.md
│ │ ├── index.md
│ │ ├── llm-integration.md
│ │ ├── local-testing.md
│ │ ├── performance-optimization.md
│ │ ├── prompting-guide.md
│ │ ├── repository-analysis.md
│ │ ├── seo-optimization.md
│ │ ├── site-monitoring.md
│ │ ├── troubleshooting.md
│ │ └── usage-examples.md
│ ├── index.md
│ ├── knowledge-graph.md
│ ├── package-lock.json
│ ├── package.json
│ ├── phase-2-intelligence.md
│ ├── reference
│ │ ├── api-overview.md
│ │ ├── cli.md
│ │ ├── configuration.md
│ │ ├── deploy-pages.md
│ │ ├── index.md
│ │ ├── mcp-tools.md
│ │ └── prompt-templates.md
│ ├── research
│ │ ├── cross-domain-integration
│ │ │ └── README.md
│ │ ├── domain-1-mcp-architecture
│ │ │ ├── index.md
│ │ │ └── mcp-performance-research.md
│ │ ├── domain-2-repository-analysis
│ │ │ └── README.md
│ │ ├── domain-3-ssg-recommendation
│ │ │ ├── index.md
│ │ │ └── ssg-performance-analysis.md
│ │ ├── domain-4-diataxis-integration
│ │ │ └── README.md
│ │ ├── domain-5-github-deployment
│ │ │ ├── github-pages-security-analysis.md
│ │ │ └── index.md
│ │ ├── domain-6-api-design
│ │ │ └── README.md
│ │ ├── README.md
│ │ ├── research-integration-summary-2025-01-14.md
│ │ ├── research-progress-template.md
│ │ └── research-questions-2025-01-14.md
│ ├── robots.txt
│ ├── sidebars.js
│ ├── sitemap.xml
│ ├── src
│ │ └── css
│ │ └── custom.css
│ └── tutorials
│ ├── development-setup.md
│ ├── environment-setup.md
│ ├── first-deployment.md
│ ├── getting-started.md
│ ├── index.md
│ ├── memory-workflows.md
│ └── user-onboarding.md
├── ISSUE_IMPLEMENTATION_SUMMARY.md
├── jest.config.js
├── LICENSE
├── Makefile
├── MCP_PHASE2_IMPLEMENTATION.md
├── mcp-config-example.json
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── release.sh
├── scripts
│ └── check-package-structure.cjs
├── SECURITY.md
├── setup-precommit.sh
├── src
│ ├── benchmarks
│ │ └── performance.ts
│ ├── index.ts
│ ├── memory
│ │ ├── contextual-retrieval.ts
│ │ ├── deployment-analytics.ts
│ │ ├── enhanced-manager.ts
│ │ ├── export-import.ts
│ │ ├── freshness-kg-integration.ts
│ │ ├── index.ts
│ │ ├── integration.ts
│ │ ├── kg-code-integration.ts
│ │ ├── kg-health.ts
│ │ ├── kg-integration.ts
│ │ ├── kg-link-validator.ts
│ │ ├── kg-storage.ts
│ │ ├── knowledge-graph.ts
│ │ ├── learning.ts
│ │ ├── manager.ts
│ │ ├── multi-agent-sharing.ts
│ │ ├── pruning.ts
│ │ ├── schemas.ts
│ │ ├── storage.ts
│ │ ├── temporal-analysis.ts
│ │ ├── user-preferences.ts
│ │ └── visualization.ts
│ ├── prompts
│ │ └── technical-writer-prompts.ts
│ ├── scripts
│ │ └── benchmark.ts
│ ├── templates
│ │ └── playwright
│ │ ├── accessibility.spec.template.ts
│ │ ├── Dockerfile.template
│ │ ├── docs-e2e.workflow.template.yml
│ │ ├── link-validation.spec.template.ts
│ │ └── playwright.config.template.ts
│ ├── tools
│ │ ├── analyze-deployments.ts
│ │ ├── analyze-readme.ts
│ │ ├── analyze-repository.ts
│ │ ├── change-watcher.ts
│ │ ├── check-documentation-links.ts
│ │ ├── cleanup-agent-artifacts.ts
│ │ ├── deploy-pages.ts
│ │ ├── detect-gaps.ts
│ │ ├── evaluate-readme-health.ts
│ │ ├── generate-config.ts
│ │ ├── generate-contextual-content.ts
│ │ ├── generate-llm-context.ts
│ │ ├── generate-readme-template.ts
│ │ ├── generate-technical-writer-prompts.ts
│ │ ├── kg-health-check.ts
│ │ ├── manage-preferences.ts
│ │ ├── manage-sitemap.ts
│ │ ├── optimize-readme.ts
│ │ ├── populate-content.ts
│ │ ├── readme-best-practices.ts
│ │ ├── recommend-ssg.ts
│ │ ├── setup-playwright-tests.ts
│ │ ├── setup-structure.ts
│ │ ├── simulate-execution.ts
│ │ ├── sync-code-to-docs.ts
│ │ ├── test-local-deployment.ts
│ │ ├── track-documentation-freshness.ts
│ │ ├── update-existing-documentation.ts
│ │ ├── validate-content.ts
│ │ ├── validate-documentation-freshness.ts
│ │ ├── validate-readme-checklist.ts
│ │ └── verify-deployment.ts
│ ├── types
│ │ └── api.ts
│ ├── utils
│ │ ├── artifact-detector.ts
│ │ ├── ast-analyzer.ts
│ │ ├── change-watcher.ts
│ │ ├── code-scanner.ts
│ │ ├── content-extractor.ts
│ │ ├── drift-detector.ts
│ │ ├── execution-simulator.ts
│ │ ├── freshness-tracker.ts
│ │ ├── language-parsers-simple.ts
│ │ ├── llm-client.ts
│ │ ├── permission-checker.ts
│ │ ├── semantic-analyzer.ts
│ │ ├── sitemap-generator.ts
│ │ ├── usage-metadata.ts
│ │ └── user-feedback-integration.ts
│ └── workflows
│ └── documentation-workflow.ts
├── test-docs-local.sh
├── tests
│ ├── api
│ │ └── mcp-responses.test.ts
│ ├── benchmarks
│ │ └── performance.test.ts
│ ├── call-graph-builder.test.ts
│ ├── change-watcher-priority.integration.test.ts
│ ├── change-watcher.test.ts
│ ├── edge-cases
│ │ └── error-handling.test.ts
│ ├── execution-simulator.test.ts
│ ├── functional
│ │ └── tools.test.ts
│ ├── integration
│ │ ├── kg-documentation-workflow.test.ts
│ │ ├── knowledge-graph-workflow.test.ts
│ │ ├── mcp-readme-tools.test.ts
│ │ ├── memory-mcp-tools.test.ts
│ │ ├── readme-technical-writer.test.ts
│ │ └── workflow.test.ts
│ ├── memory
│ │ ├── contextual-retrieval.test.ts
│ │ ├── enhanced-manager.test.ts
│ │ ├── export-import.test.ts
│ │ ├── freshness-kg-integration.test.ts
│ │ ├── kg-code-integration.test.ts
│ │ ├── kg-health.test.ts
│ │ ├── kg-link-validator.test.ts
│ │ ├── kg-storage-validation.test.ts
│ │ ├── kg-storage.test.ts
│ │ ├── knowledge-graph-documentation-examples.test.ts
│ │ ├── knowledge-graph-enhanced.test.ts
│ │ ├── knowledge-graph.test.ts
│ │ ├── learning.test.ts
│ │ ├── manager-advanced.test.ts
│ │ ├── manager.test.ts
│ │ ├── mcp-resource-integration.test.ts
│ │ ├── mcp-tool-persistence.test.ts
│ │ ├── schemas-documentation-examples.test.ts
│ │ ├── schemas.test.ts
│ │ ├── storage.test.ts
│ │ ├── temporal-analysis.test.ts
│ │ └── user-preferences.test.ts
│ ├── performance
│ │ ├── memory-load-testing.test.ts
│ │ └── memory-stress-testing.test.ts
│ ├── prompts
│ │ ├── guided-workflow-prompts.test.ts
│ │ └── technical-writer-prompts.test.ts
│ ├── server.test.ts
│ ├── setup.ts
│ ├── tools
│ │ ├── all-tools.test.ts
│ │ ├── analyze-coverage.test.ts
│ │ ├── analyze-deployments.test.ts
│ │ ├── analyze-readme.test.ts
│ │ ├── analyze-repository.test.ts
│ │ ├── check-documentation-links.test.ts
│ │ ├── cleanup-agent-artifacts.test.ts
│ │ ├── deploy-pages-kg-retrieval.test.ts
│ │ ├── deploy-pages-tracking.test.ts
│ │ ├── deploy-pages.test.ts
│ │ ├── detect-gaps.test.ts
│ │ ├── evaluate-readme-health.test.ts
│ │ ├── generate-contextual-content.test.ts
│ │ ├── generate-llm-context.test.ts
│ │ ├── generate-readme-template.test.ts
│ │ ├── generate-technical-writer-prompts.test.ts
│ │ ├── kg-health-check.test.ts
│ │ ├── manage-sitemap.test.ts
│ │ ├── optimize-readme.test.ts
│ │ ├── readme-best-practices.test.ts
│ │ ├── recommend-ssg-historical.test.ts
│ │ ├── recommend-ssg-preferences.test.ts
│ │ ├── recommend-ssg.test.ts
│ │ ├── simple-coverage.test.ts
│ │ ├── sync-code-to-docs.test.ts
│ │ ├── test-local-deployment.test.ts
│ │ ├── tool-error-handling.test.ts
│ │ ├── track-documentation-freshness.test.ts
│ │ ├── validate-content.test.ts
│ │ ├── validate-documentation-freshness.test.ts
│ │ └── validate-readme-checklist.test.ts
│ ├── types
│ │ └── type-safety.test.ts
│ └── utils
│ ├── artifact-detector.test.ts
│ ├── ast-analyzer.test.ts
│ ├── content-extractor.test.ts
│ ├── drift-detector-diataxis.test.ts
│ ├── drift-detector-priority.test.ts
│ ├── drift-detector.test.ts
│ ├── freshness-tracker.test.ts
│ ├── llm-client.test.ts
│ ├── semantic-analyzer.test.ts
│ ├── sitemap-generator.test.ts
│ ├── usage-metadata.test.ts
│ └── user-feedback-integration.test.ts
├── tsconfig.json
└── typedoc.json
```
# Files
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4 | import {
5 | CallToolRequestSchema,
6 | ListToolsRequestSchema,
7 | ListPromptsRequestSchema,
8 | GetPromptRequestSchema,
9 | ListResourcesRequestSchema,
10 | ReadResourceRequestSchema,
11 | ListRootsRequestSchema,
12 | } from "@modelcontextprotocol/sdk/types.js";
13 | import { z } from "zod";
14 | import { zodToJsonSchema } from "zod-to-json-schema";
15 | import { readFileSync } from "fs";
16 | import { fileURLToPath } from "url";
17 | import path, { dirname, join } from "path";
18 |
19 | import { analyzeRepository } from "./tools/analyze-repository.js";
20 | import { recommendSSG } from "./tools/recommend-ssg.js";
21 | import { generateConfig } from "./tools/generate-config.js";
22 | import { setupStructure } from "./tools/setup-structure.js";
23 | import { deployPages } from "./tools/deploy-pages.js";
24 | import { verifyDeployment } from "./tools/verify-deployment.js";
25 | import { setupPlaywrightTests } from "./tools/setup-playwright-tests.js";
26 | import { handlePopulateDiataxisContent } from "./tools/populate-content.js";
27 | import {
28 | handleValidateDiataxisContent,
29 | validateGeneralContent,
30 | } from "./tools/validate-content.js";
31 | import { handleUpdateExistingDocumentation } from "./tools/update-existing-documentation.js";
32 | import { detectDocumentationGaps } from "./tools/detect-gaps.js";
33 | import { testLocalDeployment } from "./tools/test-local-deployment.js";
34 | import { evaluateReadmeHealth } from "./tools/evaluate-readme-health.js";
35 | import { readmeBestPractices } from "./tools/readme-best-practices.js";
36 | import { checkDocumentationLinks } from "./tools/check-documentation-links.js";
37 | import { generateReadmeTemplate } from "./tools/generate-readme-template.js";
38 | import { validateReadmeChecklist } from "./tools/validate-readme-checklist.js";
39 | import { analyzeReadme } from "./tools/analyze-readme.js";
40 | import { optimizeReadme } from "./tools/optimize-readme.js";
41 | import { managePreferences } from "./tools/manage-preferences.js";
42 | import { analyzeDeployments } from "./tools/analyze-deployments.js";
43 | import { handleSyncCodeToDocs } from "./tools/sync-code-to-docs.js";
44 | import { handleGenerateContextualContent } from "./tools/generate-contextual-content.js";
45 | import { trackDocumentationFreshness } from "./tools/track-documentation-freshness.js";
46 | import { validateDocumentationFreshness } from "./tools/validate-documentation-freshness.js";
47 | import {
48 | changeWatcherTool,
49 | changeWatcherSchema,
50 | handleChangeWatcher,
51 | } from "./tools/change-watcher.js";
52 | import {
53 | manageSitemap,
54 | ManageSitemapInputSchema,
55 | } from "./tools/manage-sitemap.js";
56 | import {
57 | generateLLMContext,
58 | GenerateLLMContextInputSchema,
59 | setToolDefinitions,
60 | } from "./tools/generate-llm-context.js";
61 | import { cleanupAgentArtifacts } from "./tools/cleanup-agent-artifacts.js";
62 | import {
63 | handleSimulateExecution,
64 | handleBatchSimulateExecution,
65 | } from "./tools/simulate-execution.js";
66 | import { formatMCPResponse } from "./types/api.js";
67 | import {
68 | isPathAllowed,
69 | getPermissionDeniedMessage,
70 | } from "./utils/permission-checker.js";
71 | import { promises as fs } from "fs";
72 | import { generateTechnicalWriterPrompts } from "./prompts/technical-writer-prompts.js";
73 | import {
74 | DOCUMENTATION_WORKFLOWS,
75 | WORKFLOW_EXECUTION_GUIDANCE,
76 | WORKFLOW_METADATA,
77 | } from "./workflows/documentation-workflow.js";
78 | import {
79 | initializeMemory,
80 | rememberAnalysis,
81 | rememberRecommendation,
82 | getProjectInsights,
83 | getSimilarProjects,
84 | getMemoryStatistics,
85 | exportMemories,
86 | cleanupOldMemories,
87 | memoryTools,
88 | } from "./memory/index.js";
89 |
90 | // Get version from package.json
91 | const __filename = fileURLToPath(import.meta.url);
92 | const __dirname = dirname(__filename);
93 | const packageJson = JSON.parse(
94 | readFileSync(join(__dirname, "..", "package.json"), "utf-8"),
95 | );
96 |
97 | // Parse allowed roots from command line arguments
98 | const allowedRoots: string[] = [];
99 | process.argv.forEach((arg, index) => {
100 | if (arg === "--root" && process.argv[index + 1]) {
101 | const rootPath = process.argv[index + 1];
102 | // Resolve to absolute path and expand ~ for home directory
103 | const expandedPath = rootPath.startsWith("~")
104 | ? join(
105 | process.env.HOME || process.env.USERPROFILE || "",
106 | rootPath.slice(1),
107 | )
108 | : rootPath;
109 | allowedRoots.push(path.resolve(expandedPath));
110 | }
111 | });
112 |
113 | // If no roots specified, allow current working directory by default
114 | if (allowedRoots.length === 0) {
115 | allowedRoots.push(process.cwd());
116 | }
117 |
118 | // Server initialization with Code Mode optimization (ADR-011)
119 | // Optimized for Code Mode workflows with 25+ composable tools,
120 | // MCP Resources for efficient context management, and Diataxis framework support.
121 | // Achieves 98% token reduction through resource-based result filtering.
122 | const server = new Server(
123 | {
124 | name: "documcp",
125 | version: packageJson.version,
126 | },
127 | {
128 | capabilities: {
129 | tools: {},
130 | prompts: {
131 | listChanged: true,
132 | },
133 | resources: {
134 | subscribe: true,
135 | listChanged: true,
136 | },
137 | roots: {
138 | listChanged: true,
139 | },
140 | },
141 | },
142 | );
143 |
144 | // Code Mode prompt generator for orchestration workflows (ADR-011)
145 | function generateCodeModePrompt(
146 | name: string,
147 | projectPath: string,
148 | args: Record<string, any>,
149 | ) {
150 | const baseContext = `Project path: ${projectPath}`;
151 |
152 | switch (name) {
153 | case "code-mode-documentation-setup":
154 | return {
155 | description:
156 | "Complete documentation setup using efficient code-based orchestration",
157 | messages: [
158 | {
159 | role: "user" as const,
160 | content: {
161 | type: "text" as const,
162 | text: `${baseContext}
163 |
164 | You are a documentation automation expert using the documcp MCP server in Code Mode. Write TypeScript code to orchestrate a complete documentation setup workflow.
165 |
166 | **Requirements:**
167 | - Use documcp tools via the MCP client API
168 | - Leverage parallel execution where possible (e.g., Promise.all for independent operations)
169 | - Store intermediate results as MCP resources (not in LLM context)
170 | - Return only summary data, not full analysis results
171 | - Handle errors gracefully with try-catch blocks
172 |
173 | **Workflow Steps:**
174 | 1. Analyze repository using analyze_repository tool
175 | 2. Get SSG recommendation using recommend_ssg tool (with analysis results)
176 | 3. Generate configuration files using generate_config tool
177 | 4. Create Diataxis structure using setup_structure tool
178 | 5. ${
179 | args.include_deployment !== "false"
180 | ? "Set up GitHub Pages deployment using deploy_pages tool"
181 | : "Skip deployment setup"
182 | }
183 | 6. Return concise summary of completed setup
184 |
185 | **Example Pattern:**
186 | \`\`\`typescript
187 | // Step 1: Analysis (returns resource URI, not full data)
188 | const analysisResult = await callTool('analyze_repository', { path: '${projectPath}', depth: 'standard' });
189 | const analysisUri = analysisResult.resourceUri; // Store reference, not full data
190 |
191 | // Step 2: Recommendation (uses cached analysis)
192 | const recommendation = await callTool('recommend_ssg', { analysisId: analysisResult.analysisId });
193 | const selectedSSG = ${
194 | args.ssg_preference && args.ssg_preference !== "auto-detect"
195 | ? `'${args.ssg_preference}'`
196 | : "recommendation.primary"
197 | };
198 |
199 | // Step 3-4: Parallel execution for speed
200 | const [config, structure] = await Promise.all([
201 | callTool('generate_config', { ssg: selectedSSG, projectName: '${projectPath
202 | .split("/")
203 | .pop()}', outputPath: '${projectPath}' }),
204 | callTool('setup_structure', { path: '${projectPath}', ssg: selectedSSG })
205 | ]);
206 |
207 | // Return summary only (not gigabytes of data!)
208 | return { success: true, ssg: selectedSSG, configFiles: config.files.length, docsCreated: structure.filesCreated };
209 | \`\`\`
210 |
211 | Write the complete orchestration code now.`,
212 | },
213 | },
214 | ],
215 | };
216 |
217 | case "code-mode-parallel-workflow": {
218 | const operations = args.operations || "analysis,validation,freshness";
219 | return {
220 | description:
221 | "Execute multiple documcp operations in parallel for maximum efficiency",
222 | messages: [
223 | {
224 | role: "user" as const,
225 | content: {
226 | type: "text" as const,
227 | text: `${baseContext}
228 |
229 | You are a documentation automation expert using the documcp MCP server in Code Mode. Write TypeScript code to execute multiple operations in parallel for maximum efficiency.
230 |
231 | **Operations to run:** ${operations}
232 |
233 | **Code Mode Best Practices:**
234 | - Use Promise.all() for parallel execution of independent operations
235 | - Store large results as MCP resources (resource URIs only in context)
236 | - Return concise summaries, not full data
237 | - Handle partial failures gracefully (Promise.allSettled)
238 |
239 | **Example Pattern:**
240 | \`\`\`typescript
241 | const operations = await Promise.allSettled([
242 | ${
243 | operations.includes("analysis")
244 | ? "callTool('analyze_repository', { path: '" +
245 | projectPath +
246 | "', depth: 'quick' }),"
247 | : ""
248 | }
249 | ${
250 | operations.includes("validation")
251 | ? "callTool('validate_diataxis_content', { contentPath: '" +
252 | projectPath +
253 | "/docs' }),"
254 | : ""
255 | }
256 | ${
257 | operations.includes("freshness")
258 | ? "callTool('track_documentation_freshness', { docsPath: '" +
259 | projectPath +
260 | "/docs', preset: 'monthly' }),"
261 | : ""
262 | }
263 | ${
264 | operations.includes("gap-detection")
265 | ? "callTool('detect_documentation_gaps', { repositoryPath: '" +
266 | projectPath +
267 | "' }),"
268 | : ""
269 | }
270 | ${
271 | operations.includes("link-checking")
272 | ? "callTool('check_documentation_links', { documentation_path: '" +
273 | projectPath +
274 | "/docs' }),"
275 | : ""
276 | }
277 | ]);
278 |
279 | // Extract summaries (not full data!)
280 | const results = operations.map((op, i) => ({
281 | operation: ['${operations.replace(/,/g, "', '")}'][i],
282 | status: op.status,
283 | summary: op.status === 'fulfilled' ? extractSummary(op.value) : op.reason.message
284 | }));
285 |
286 | return { parallelOperations: ${
287 | operations.split(",").length
288 | }, completed: results.filter(r => r.status === 'fulfilled').length, results };
289 | \`\`\`
290 |
291 | Write the complete parallel orchestration code now.`,
292 | },
293 | },
294 | ],
295 | };
296 | }
297 |
298 | case "code-mode-efficient-analysis":
299 | return {
300 | description:
301 | "Comprehensive project analysis with resource-based result filtering",
302 | messages: [
303 | {
304 | role: "user" as const,
305 | content: {
306 | type: "text" as const,
307 | text: `${baseContext}
308 |
309 | You are a documentation automation expert using the documcp MCP server in Code Mode. Write TypeScript code for efficient project analysis using resource-based result filtering.
310 |
311 | **Goal:** Analyze project comprehensively but keep LLM context minimal (use resources for large data).
312 |
313 | **Code Mode Efficiency Pattern:**
314 | \`\`\`typescript
315 | // Step 1: Deep analysis (returns resource URI for full data)
316 | const analysis = await callTool('analyze_repository', {
317 | path: '${projectPath}',
318 | depth: 'deep' // Full analysis, but results stored as resource
319 | });
320 |
321 | // Access only summary in context (not 50,000 tokens of data!)
322 | const summary = {
323 | fileCount: analysis.fileCount,
324 | primaryLanguage: analysis.primaryLanguage,
325 | complexity: analysis.complexityScore,
326 | resourceUri: analysis.resourceUri // Full data available via resource
327 | };
328 |
329 | ${
330 | args.include_recommendations !== "false"
331 | ? `
332 | // Step 2: Get recommendations (optional)
333 | const recommendation = await callTool('recommend_ssg', {
334 | analysisId: analysis.analysisId,
335 | userId: 'default'
336 | });
337 |
338 | return { analysis: summary, recommendation: recommendation.primary, confidence: recommendation.confidence };
339 | `
340 | : `
341 | return { analysis: summary, message: 'Full analysis available via resource URI' };
342 | `
343 | }
344 | \`\`\`
345 |
346 | **Key Benefits:**
347 | - Full analysis performed, but only summary in LLM context
348 | - 98% token reduction (50,000 tokens → 500 tokens)
349 | - 75x cost reduction for complex workflows
350 | - Full data still accessible via resource URI when needed
351 |
352 | Write the complete efficient analysis code now.`,
353 | },
354 | },
355 | ],
356 | };
357 |
358 | default:
359 | return {
360 | description: "Code Mode orchestration prompt",
361 | messages: [
362 | {
363 | role: "user" as const,
364 | content: {
365 | type: "text" as const,
366 | text: `Unsupported Code Mode prompt: ${name}`,
367 | },
368 | },
369 | ],
370 | };
371 | }
372 | }
373 |
374 | // Tool definitions following ADR-006
375 | const TOOLS = [
376 | {
377 | name: "analyze_repository",
378 | description:
379 | "Analyze repository structure, dependencies, and documentation needs",
380 | inputSchema: z.object({
381 | path: z.string().describe("Path to the repository to analyze"),
382 | depth: z
383 | .enum(["quick", "standard", "deep"])
384 | .optional()
385 | .default("standard"),
386 | }),
387 | },
388 | {
389 | name: "recommend_ssg",
390 | description:
391 | "Recommend the best static site generator based on project analysis and user preferences",
392 | inputSchema: z.object({
393 | analysisId: z.string().describe("ID from previous repository analysis"),
394 | userId: z
395 | .string()
396 | .optional()
397 | .default("default")
398 | .describe(
399 | "User ID for personalized recommendations based on usage history",
400 | ),
401 | preferences: z
402 | .object({
403 | priority: z
404 | .enum(["simplicity", "features", "performance"])
405 | .optional(),
406 | ecosystem: z
407 | .enum(["javascript", "python", "ruby", "go", "any"])
408 | .optional(),
409 | })
410 | .optional(),
411 | }),
412 | },
413 | {
414 | name: "generate_config",
415 | description:
416 | "Generate configuration files for the selected static site generator",
417 | inputSchema: z.object({
418 | ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
419 | projectName: z.string(),
420 | projectDescription: z.string().optional(),
421 | outputPath: z.string().describe("Where to generate config files"),
422 | }),
423 | },
424 | {
425 | name: "setup_structure",
426 | description: "Create Diataxis-compliant documentation structure",
427 | inputSchema: z.object({
428 | path: z.string().describe("Root path for documentation"),
429 | ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
430 | includeExamples: z.boolean().optional().default(true),
431 | }),
432 | },
433 | {
434 | name: "setup_playwright_tests",
435 | description:
436 | "Generate Playwright E2E test setup for documentation site (containers + CI/CD)",
437 | inputSchema: z.object({
438 | repositoryPath: z.string().describe("Path to documentation repository"),
439 | ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
440 | projectName: z.string().describe("Project name for tests"),
441 | mainBranch: z.string().optional().default("main"),
442 | includeAccessibilityTests: z.boolean().optional().default(true),
443 | includeDockerfile: z.boolean().optional().default(true),
444 | includeGitHubActions: z.boolean().optional().default(true),
445 | }),
446 | },
447 | {
448 | name: "deploy_pages",
449 | description:
450 | "Set up GitHub Pages deployment workflow with deployment tracking and preference learning",
451 | inputSchema: z.object({
452 | repository: z.string().describe("Repository path or URL"),
453 | ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
454 | branch: z.string().optional().default("gh-pages"),
455 | customDomain: z.string().optional(),
456 | projectPath: z
457 | .string()
458 | .optional()
459 | .describe("Local path to the project for tracking"),
460 | projectName: z.string().optional().describe("Project name for tracking"),
461 | analysisId: z
462 | .string()
463 | .optional()
464 | .describe("ID from repository analysis for linking"),
465 | userId: z
466 | .string()
467 | .optional()
468 | .default("default")
469 | .describe("User ID for preference tracking"),
470 | }),
471 | },
472 | {
473 | name: "verify_deployment",
474 | description: "Verify and troubleshoot GitHub Pages deployment",
475 | inputSchema: z.object({
476 | repository: z.string().describe("Repository path or URL"),
477 | url: z.string().optional().describe("Expected deployment URL"),
478 | }),
479 | },
480 | {
481 | name: "populate_diataxis_content",
482 | description:
483 | "Intelligently populate Diataxis documentation with project-specific content",
484 | inputSchema: z.object({
485 | analysisId: z
486 | .string()
487 | .describe("Repository analysis ID from analyze_repository tool"),
488 | docsPath: z.string().describe("Path to documentation directory"),
489 | populationLevel: z
490 | .enum(["basic", "comprehensive", "intelligent"])
491 | .optional()
492 | .default("comprehensive"),
493 | includeProjectSpecific: z.boolean().optional().default(true),
494 | preserveExisting: z.boolean().optional().default(true),
495 | technologyFocus: z
496 | .array(z.string())
497 | .optional()
498 | .describe("Specific technologies to emphasize"),
499 | }),
500 | },
501 | {
502 | name: "update_existing_documentation",
503 | description:
504 | "Intelligently analyze and update existing documentation using memory insights and code comparison",
505 | inputSchema: z.object({
506 | analysisId: z
507 | .string()
508 | .describe("Repository analysis ID from analyze_repository tool"),
509 | docsPath: z.string().describe("Path to existing documentation directory"),
510 | compareMode: z
511 | .enum(["comprehensive", "gap-detection", "accuracy-check"])
512 | .optional()
513 | .default("comprehensive")
514 | .describe("Mode of comparison between code and documentation"),
515 | updateStrategy: z
516 | .enum(["conservative", "moderate", "aggressive"])
517 | .optional()
518 | .default("moderate")
519 | .describe("How aggressively to suggest updates"),
520 | preserveStyle: z
521 | .boolean()
522 | .optional()
523 | .default(true)
524 | .describe("Preserve existing documentation style and formatting"),
525 | focusAreas: z
526 | .array(z.string())
527 | .optional()
528 | .describe(
529 | 'Specific areas to focus updates on (e.g., "dependencies", "scripts", "api")',
530 | ),
531 | }),
532 | },
533 | {
534 | name: "validate_diataxis_content",
535 | description:
536 | "Validate the accuracy, completeness, and compliance of generated Diataxis documentation",
537 | inputSchema: z.object({
538 | contentPath: z
539 | .string()
540 | .describe("Path to the documentation directory to validate"),
541 | analysisId: z
542 | .string()
543 | .optional()
544 | .describe(
545 | "Optional repository analysis ID for context-aware validation",
546 | ),
547 | validationType: z
548 | .enum(["accuracy", "completeness", "compliance", "all"])
549 | .optional()
550 | .default("all")
551 | .describe(
552 | "Type of validation: accuracy, completeness, compliance, or all",
553 | ),
554 | includeCodeValidation: z
555 | .boolean()
556 | .optional()
557 | .default(true)
558 | .describe("Whether to validate code examples"),
559 | confidence: z
560 | .enum(["strict", "moderate", "permissive"])
561 | .optional()
562 | .default("moderate")
563 | .describe(
564 | "Validation confidence level: strict, moderate, or permissive",
565 | ),
566 | }),
567 | },
568 | {
569 | name: "validate_content",
570 | description:
571 | "Validate general content quality: broken links, code syntax, references, and basic accuracy",
572 | inputSchema: z.object({
573 | contentPath: z
574 | .string()
575 | .describe("Path to the content directory to validate"),
576 | validationType: z
577 | .string()
578 | .optional()
579 | .default("all")
580 | .describe("Type of validation: links, code, references, or all"),
581 | includeCodeValidation: z
582 | .boolean()
583 | .optional()
584 | .default(true)
585 | .describe("Whether to validate code blocks"),
586 | followExternalLinks: z
587 | .boolean()
588 | .optional()
589 | .default(false)
590 | .describe("Whether to validate external URLs (slower)"),
591 | }),
592 | },
593 | {
594 | name: "detect_documentation_gaps",
595 | description:
596 | "Analyze repository and existing documentation to identify missing content and gaps",
597 | inputSchema: z.object({
598 | repositoryPath: z.string().describe("Path to the repository to analyze"),
599 | documentationPath: z
600 | .string()
601 | .optional()
602 | .describe("Path to existing documentation (if any)"),
603 | analysisId: z
604 | .string()
605 | .optional()
606 | .describe("Optional existing analysis ID to reuse"),
607 | depth: z
608 | .enum(["quick", "standard", "comprehensive"])
609 | .optional()
610 | .default("standard"),
611 | }),
612 | },
613 | {
614 | name: "test_local_deployment",
615 | description:
616 | "Test documentation build and local server before deploying to GitHub Pages",
617 | inputSchema: z.object({
618 | repositoryPath: z.string().describe("Path to the repository"),
619 | ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
620 | port: z
621 | .number()
622 | .optional()
623 | .default(3000)
624 | .describe("Port for local server"),
625 | timeout: z
626 | .number()
627 | .optional()
628 | .default(60)
629 | .describe("Timeout in seconds for build process"),
630 | skipBuild: z
631 | .boolean()
632 | .optional()
633 | .default(false)
634 | .describe("Skip build step and only start server"),
635 | }),
636 | },
637 | {
638 | name: "evaluate_readme_health",
639 | description:
640 | "Evaluate README files for community health, accessibility, and onboarding effectiveness",
641 | inputSchema: z.object({
642 | readme_path: z.string().describe("Path to the README file to evaluate"),
643 | project_type: z
644 | .enum([
645 | "community_library",
646 | "enterprise_tool",
647 | "personal_project",
648 | "documentation",
649 | ])
650 | .optional()
651 | .default("community_library")
652 | .describe("Type of project for tailored evaluation"),
653 | repository_path: z
654 | .string()
655 | .optional()
656 | .describe("Optional path to repository for additional context"),
657 | }),
658 | },
659 | {
660 | name: "readme_best_practices",
661 | description:
662 | "Analyze README files against best practices checklist and generate templates for improvement",
663 | inputSchema: z.object({
664 | readme_path: z.string().describe("Path to the README file to analyze"),
665 | project_type: z
666 | .enum(["library", "application", "tool", "documentation", "framework"])
667 | .optional()
668 | .default("library")
669 | .describe("Type of project for tailored analysis"),
670 | generate_template: z
671 | .boolean()
672 | .optional()
673 | .default(false)
674 | .describe("Generate README templates and community files"),
675 | output_directory: z
676 | .string()
677 | .optional()
678 | .describe("Directory to write generated templates and community files"),
679 | include_community_files: z
680 | .boolean()
681 | .optional()
682 | .default(true)
683 | .describe(
684 | "Generate community health files (CONTRIBUTING.md, CODE_OF_CONDUCT.md, etc.)",
685 | ),
686 | target_audience: z
687 | .enum(["beginner", "intermediate", "advanced", "mixed"])
688 | .optional()
689 | .default("mixed")
690 | .describe("Target audience for recommendations"),
691 | }),
692 | },
693 | {
694 | name: "check_documentation_links",
695 | description:
696 | "Comprehensive link checking for documentation deployment with external, internal, and anchor link validation",
697 | inputSchema: z.object({
698 | documentation_path: z
699 | .string()
700 | .optional()
701 | .default("./docs")
702 | .describe("Path to the documentation directory to check"),
703 | check_external_links: z
704 | .boolean()
705 | .optional()
706 | .default(true)
707 | .describe("Validate external URLs (slower but comprehensive)"),
708 | check_internal_links: z
709 | .boolean()
710 | .optional()
711 | .default(true)
712 | .describe("Validate internal file references"),
713 | check_anchor_links: z
714 | .boolean()
715 | .optional()
716 | .default(true)
717 | .describe("Validate anchor links within documents"),
718 | timeout_ms: z
719 | .number()
720 | .min(1000)
721 | .max(30000)
722 | .optional()
723 | .default(5000)
724 | .describe("Timeout for external link requests in milliseconds"),
725 | max_concurrent_checks: z
726 | .number()
727 | .min(1)
728 | .max(20)
729 | .optional()
730 | .default(5)
731 | .describe("Maximum concurrent link checks"),
732 | allowed_domains: z
733 | .array(z.string())
734 | .optional()
735 | .default([])
736 | .describe(
737 | "Whitelist of allowed external domains (empty = all allowed)",
738 | ),
739 | ignore_patterns: z
740 | .array(z.string())
741 | .optional()
742 | .default([])
743 | .describe("URL patterns to ignore during checking"),
744 | fail_on_broken_links: z
745 | .boolean()
746 | .optional()
747 | .default(false)
748 | .describe("Fail the check if broken links are found"),
749 | output_format: z
750 | .enum(["summary", "detailed", "json"])
751 | .optional()
752 | .default("detailed")
753 | .describe("Output format for results"),
754 | }),
755 | },
756 | {
757 | name: "generate_readme_template",
758 | description:
759 | "Generate standardized README templates for different project types with best practices",
760 | inputSchema: z.object({
761 | projectName: z.string().min(1).describe("Name of the project"),
762 | description: z
763 | .string()
764 | .min(1)
765 | .describe("Brief description of what the project does"),
766 | templateType: z
767 | .enum(["library", "application", "cli-tool", "api", "documentation"])
768 | .describe("Type of project template to generate"),
769 | author: z
770 | .string()
771 | .optional()
772 | .describe("Project author/organization name"),
773 | license: z.string().optional().default("MIT").describe("Project license"),
774 | includeScreenshots: z
775 | .boolean()
776 | .optional()
777 | .default(false)
778 | .describe("Include screenshot placeholders for applications"),
779 | includeBadges: z
780 | .boolean()
781 | .optional()
782 | .default(true)
783 | .describe("Include status badges"),
784 | includeContributing: z
785 | .boolean()
786 | .optional()
787 | .default(true)
788 | .describe("Include contributing section"),
789 | outputPath: z
790 | .string()
791 | .optional()
792 | .describe("Path to write the generated README.md file"),
793 | }),
794 | },
795 | {
796 | name: "validate_readme_checklist",
797 | description:
798 | "Validate README files against community best practices checklist with detailed scoring",
799 | inputSchema: z.object({
800 | readmePath: z
801 | .string()
802 | .min(1)
803 | .describe("Path to the README file to validate"),
804 | projectPath: z
805 | .string()
806 | .optional()
807 | .describe("Path to project directory for additional context"),
808 | strict: z
809 | .boolean()
810 | .optional()
811 | .default(false)
812 | .describe("Use strict validation rules"),
813 | outputFormat: z
814 | .enum(["json", "markdown", "console"])
815 | .optional()
816 | .default("console")
817 | .describe("Output format for the validation report"),
818 | }),
819 | },
820 | {
821 | name: "analyze_readme",
822 | description:
823 | "Comprehensive README analysis with length assessment, structure evaluation, and optimization opportunities",
824 | inputSchema: z.object({
825 | project_path: z
826 | .string()
827 | .min(1)
828 | .describe("Path to the project directory containing README"),
829 | target_audience: z
830 | .enum([
831 | "community_contributors",
832 | "enterprise_users",
833 | "developers",
834 | "general",
835 | ])
836 | .optional()
837 | .default("community_contributors")
838 | .describe("Target audience for analysis"),
839 | optimization_level: z
840 | .enum(["light", "moderate", "aggressive"])
841 | .optional()
842 | .default("moderate")
843 | .describe("Level of optimization suggestions"),
844 | max_length_target: z
845 | .number()
846 | .min(50)
847 | .max(1000)
848 | .optional()
849 | .default(300)
850 | .describe("Target maximum length in lines"),
851 | }),
852 | },
853 | {
854 | name: "optimize_readme",
855 | description:
856 | "Optimize README content by restructuring, condensing, and extracting detailed sections to separate documentation",
857 | inputSchema: z.object({
858 | readme_path: z
859 | .string()
860 | .min(1)
861 | .describe("Path to the README file to optimize"),
862 | strategy: z
863 | .enum([
864 | "community_focused",
865 | "enterprise_focused",
866 | "developer_focused",
867 | "general",
868 | ])
869 | .optional()
870 | .default("community_focused")
871 | .describe("Optimization strategy"),
872 | max_length: z
873 | .number()
874 | .min(50)
875 | .max(1000)
876 | .optional()
877 | .default(300)
878 | .describe("Target maximum length in lines"),
879 | include_tldr: z
880 | .boolean()
881 | .optional()
882 | .default(true)
883 | .describe("Generate and include TL;DR section"),
884 | preserve_existing: z
885 | .boolean()
886 | .optional()
887 | .default(true)
888 | .describe("Preserve existing content structure where possible"),
889 | output_path: z
890 | .string()
891 | .optional()
892 | .describe(
893 | "Path to write optimized README (if not specified, returns content only)",
894 | ),
895 | create_docs_directory: z
896 | .boolean()
897 | .optional()
898 | .default(true)
899 | .describe("Create docs/ directory for extracted content"),
900 | }),
901 | },
902 | {
903 | name: "manage_preferences",
904 | description:
905 | "Manage user preferences for documentation generation and SSG recommendations",
906 | inputSchema: z.object({
907 | action: z
908 | .enum(["get", "update", "reset", "export", "import", "recommendations"])
909 | .describe("Action to perform on preferences"),
910 | userId: z
911 | .string()
912 | .optional()
913 | .default("default")
914 | .describe("User ID for multi-user setups"),
915 | preferences: z
916 | .object({
917 | preferredSSGs: z
918 | .array(z.string())
919 | .optional()
920 | .describe("List of preferred static site generators"),
921 | documentationStyle: z
922 | .enum(["minimal", "comprehensive", "tutorial-heavy"])
923 | .optional()
924 | .describe("Preferred documentation style"),
925 | expertiseLevel: z
926 | .enum(["beginner", "intermediate", "advanced"])
927 | .optional()
928 | .describe("User's technical expertise level"),
929 | preferredTechnologies: z
930 | .array(z.string())
931 | .optional()
932 | .describe("Preferred technologies and frameworks"),
933 | preferredDiataxisCategories: z
934 | .array(z.enum(["tutorials", "how-to", "reference", "explanation"]))
935 | .optional()
936 | .describe("Preferred Diataxis documentation categories"),
937 | autoApplyPreferences: z
938 | .boolean()
939 | .optional()
940 | .describe("Automatically apply preferences to recommendations"),
941 | })
942 | .optional()
943 | .describe("Preference updates (for update action)"),
944 | json: z.string().optional().describe("JSON string for import action"),
945 | }),
946 | },
947 | {
948 | name: "analyze_deployments",
949 | description:
950 | "Analyze deployment patterns and generate insights from historical deployment data",
951 | inputSchema: z.object({
952 | analysisType: z
953 | .enum(["full_report", "ssg_stats", "compare", "health", "trends"])
954 | .optional()
955 | .default("full_report")
956 | .describe(
957 | "Type of analysis: full_report (comprehensive), ssg_stats (per-SSG), compare (compare SSGs), health (deployment health score), trends (temporal analysis)",
958 | ),
959 | ssg: z.string().optional().describe("SSG name for ssg_stats analysis"),
960 | ssgs: z
961 | .array(z.string())
962 | .optional()
963 | .describe("Array of SSG names for comparison"),
964 | periodDays: z
965 | .number()
966 | .optional()
967 | .default(30)
968 | .describe("Period in days for trend analysis"),
969 | }),
970 | },
971 | {
972 | name: "read_directory",
973 | description:
974 | "List files and directories within allowed roots. Use this to discover files without requiring full absolute paths from the user.",
975 | inputSchema: z.object({
976 | path: z
977 | .string()
978 | .describe(
979 | "Path to directory (relative to root or absolute within root)",
980 | ),
981 | }),
982 | },
983 | // Phase 3: Code-to-Documentation Synchronization
984 | {
985 | name: "sync_code_to_docs",
986 | description:
987 | "Automatically synchronize documentation with code changes using AST-based drift detection (Phase 3)",
988 | inputSchema: z.object({
989 | projectPath: z.string().describe("Path to the project root directory"),
990 | docsPath: z.string().describe("Path to the documentation directory"),
991 | mode: z
992 | .enum(["detect", "preview", "apply", "auto"])
993 | .default("detect")
994 | .describe(
995 | "Sync mode: detect=analyze only, preview=show changes, apply=apply safe changes, auto=apply all",
996 | ),
997 | autoApplyThreshold: z
998 | .number()
999 | .min(0)
1000 | .max(1)
1001 | .default(0.8)
1002 | .describe(
1003 | "Confidence threshold (0-1) for automatic application of changes",
1004 | ),
1005 | createSnapshot: z
1006 | .boolean()
1007 | .default(true)
1008 | .describe("Create a snapshot before making changes (recommended)"),
1009 | }),
1010 | },
1011 | {
1012 | name: changeWatcherTool.name,
1013 | description: changeWatcherTool.description,
1014 | inputSchema: changeWatcherSchema,
1015 | },
1016 | {
1017 | name: "generate_contextual_content",
1018 | description:
1019 | "Generate context-aware documentation using AST analysis and knowledge graph insights (Phase 3)",
1020 | inputSchema: z.object({
1021 | filePath: z.string().describe("Path to the source code file to document"),
1022 | documentationType: z
1023 | .enum(["tutorial", "how-to", "reference", "explanation", "all"])
1024 | .default("reference")
1025 | .describe("Type of Diataxis documentation to generate"),
1026 | includeExamples: z
1027 | .boolean()
1028 | .default(true)
1029 | .describe("Include code examples in generated documentation"),
1030 | style: z
1031 | .enum(["concise", "detailed", "verbose"])
1032 | .default("detailed")
1033 | .describe("Documentation detail level"),
1034 | outputFormat: z
1035 | .enum(["markdown", "mdx", "html"])
1036 | .default("markdown")
1037 | .describe("Output format for generated content"),
1038 | }),
1039 | },
1040 | // Execution Simulation (Issue #73)
1041 | {
1042 | name: "simulate_execution",
1043 | description:
1044 | "Simulate code execution using LLM to trace execution paths without running the code. " +
1045 | "Validates documentation examples by predicting behavior, detecting potential issues " +
1046 | "(null references, type mismatches, unreachable code), and comparing against expected results. " +
1047 | "Supports building call graphs for complex execution path analysis.",
1048 | inputSchema: z.object({
1049 | exampleCode: z
1050 | .string()
1051 | .describe("The code example to simulate (from documentation)"),
1052 | implementationCode: z
1053 | .string()
1054 | .optional()
1055 | .describe(
1056 | "The actual implementation code to trace against (if not using implementationPath)",
1057 | ),
1058 | implementationPath: z
1059 | .string()
1060 | .optional()
1061 | .describe(
1062 | "Path to the implementation file (alternative to implementationCode)",
1063 | ),
1064 | entryPoint: z
1065 | .string()
1066 | .optional()
1067 | .describe(
1068 | "Function name to start tracing from (auto-detected if not provided)",
1069 | ),
1070 | expectedBehavior: z
1071 | .string()
1072 | .optional()
1073 | .describe("Description of expected behavior for validation"),
1074 | options: z
1075 | .object({
1076 | maxDepth: z
1077 | .number()
1078 | .optional()
1079 | .describe("Maximum call depth to trace (default: 10)"),
1080 | maxSteps: z
1081 | .number()
1082 | .optional()
1083 | .describe("Maximum execution steps to simulate (default: 100)"),
1084 | timeoutMs: z
1085 | .number()
1086 | .optional()
1087 | .describe(
1088 | "Timeout for simulation in milliseconds (default: 30000)",
1089 | ),
1090 | includeCallGraph: z
1091 | .boolean()
1092 | .optional()
1093 | .describe("Include call graph in results (default: true)"),
1094 | detectNullRefs: z
1095 | .boolean()
1096 | .optional()
1097 | .describe(
1098 | "Detect potential null/undefined references (default: true)",
1099 | ),
1100 | detectTypeMismatches: z
1101 | .boolean()
1102 | .optional()
1103 | .describe("Detect type mismatches (default: true)"),
1104 | detectUnreachableCode: z
1105 | .boolean()
1106 | .optional()
1107 | .describe("Detect unreachable code (default: true)"),
1108 | confidenceThreshold: z
1109 | .number()
1110 | .optional()
1111 | .describe("Minimum confidence threshold (0-1, default: 0.7)"),
1112 | })
1113 | .optional(),
1114 | }),
1115 | },
1116 | {
1117 | name: "batch_simulate_execution",
1118 | description:
1119 | "Simulate execution of multiple code examples in batch. " +
1120 | "Useful for validating all examples in a documentation file at once.",
1121 | inputSchema: z.object({
1122 | examples: z
1123 | .array(
1124 | z.object({
1125 | code: z.string().describe("The code example"),
1126 | implementationPath: z
1127 | .string()
1128 | .optional()
1129 | .describe("Path to implementation file"),
1130 | expectedBehavior: z
1131 | .string()
1132 | .optional()
1133 | .describe("Expected behavior description"),
1134 | }),
1135 | )
1136 | .describe("Array of examples to simulate"),
1137 | globalOptions: z
1138 | .object({
1139 | maxDepth: z.number().optional(),
1140 | maxSteps: z.number().optional(),
1141 | timeoutMs: z.number().optional(),
1142 | includeCallGraph: z.boolean().optional(),
1143 | detectNullRefs: z.boolean().optional(),
1144 | detectTypeMismatches: z.boolean().optional(),
1145 | detectUnreachableCode: z.boolean().optional(),
1146 | confidenceThreshold: z.number().optional(),
1147 | })
1148 | .optional()
1149 | .describe("Options applied to all simulations"),
1150 | }),
1151 | },
1152 | // Documentation Freshness Tracking
1153 | {
1154 | name: "track_documentation_freshness",
1155 | description:
1156 | "Scan documentation directory for staleness markers and identify files needing updates based on configurable time thresholds (minutes, hours, days)",
1157 | inputSchema: z.object({
1158 | docsPath: z.string().describe("Path to documentation directory"),
1159 | projectPath: z
1160 | .string()
1161 | .optional()
1162 | .describe("Path to project root (for knowledge graph tracking)"),
1163 | warningThreshold: z
1164 | .object({
1165 | value: z.number().positive(),
1166 | unit: z.enum(["minutes", "hours", "days"]),
1167 | })
1168 | .optional()
1169 | .describe("Warning threshold (yellow flag)"),
1170 | staleThreshold: z
1171 | .object({
1172 | value: z.number().positive(),
1173 | unit: z.enum(["minutes", "hours", "days"]),
1174 | })
1175 | .optional()
1176 | .describe("Stale threshold (orange flag)"),
1177 | criticalThreshold: z
1178 | .object({
1179 | value: z.number().positive(),
1180 | unit: z.enum(["minutes", "hours", "days"]),
1181 | })
1182 | .optional()
1183 | .describe("Critical threshold (red flag)"),
1184 | preset: z
1185 | .enum([
1186 | "realtime",
1187 | "active",
1188 | "recent",
1189 | "weekly",
1190 | "monthly",
1191 | "quarterly",
1192 | ])
1193 | .optional()
1194 | .describe("Use predefined threshold preset"),
1195 | includeFileList: z
1196 | .boolean()
1197 | .optional()
1198 | .default(true)
1199 | .describe("Include detailed file list in response"),
1200 | sortBy: z
1201 | .enum(["age", "path", "staleness"])
1202 | .optional()
1203 | .default("staleness")
1204 | .describe("Sort order for file list"),
1205 | storeInKG: z
1206 | .boolean()
1207 | .optional()
1208 | .default(true)
1209 | .describe(
1210 | "Store tracking event in knowledge graph for historical analysis",
1211 | ),
1212 | }),
1213 | },
1214 | {
1215 | name: "validate_documentation_freshness",
1216 | description:
1217 | "Validate documentation freshness, initialize metadata for files without it, and update timestamps based on code changes",
1218 | inputSchema: z.object({
1219 | docsPath: z.string().describe("Path to documentation directory"),
1220 | projectPath: z
1221 | .string()
1222 | .describe("Path to project root (for git integration)"),
1223 | initializeMissing: z
1224 | .boolean()
1225 | .optional()
1226 | .default(true)
1227 | .describe("Initialize metadata for files without it"),
1228 | updateExisting: z
1229 | .boolean()
1230 | .optional()
1231 | .default(false)
1232 | .describe("Update last_validated timestamp for all files"),
1233 | updateFrequency: z
1234 | .enum([
1235 | "realtime",
1236 | "active",
1237 | "recent",
1238 | "weekly",
1239 | "monthly",
1240 | "quarterly",
1241 | ])
1242 | .optional()
1243 | .default("monthly")
1244 | .describe("Default update frequency for new metadata"),
1245 | validateAgainstGit: z
1246 | .boolean()
1247 | .optional()
1248 | .default(true)
1249 | .describe("Validate against current git commit"),
1250 | }),
1251 | },
1252 | {
1253 | name: "manage_sitemap",
1254 | description:
1255 | "Generate, validate, and manage sitemap.xml as the source of truth for documentation links. Sitemap.xml is used for SEO, search engine submission, and deployment tracking.",
1256 | inputSchema: ManageSitemapInputSchema,
1257 | },
1258 | {
1259 | name: "generate_llm_context",
1260 | description:
1261 | "Generate a comprehensive LLM context reference file documenting all tools, memory system, and workflows for easy @ reference",
1262 | inputSchema: GenerateLLMContextInputSchema,
1263 | },
1264 | {
1265 | name: "cleanup_agent_artifacts",
1266 | description:
1267 | "Detect, classify, and clean up artifacts generated by AI coding agents (e.g., TODO.md, PLAN.md, agent markers, temporary files). Supports scan, clean, and archive operations with configurable patterns.",
1268 | inputSchema: z.object({
1269 | path: z.string().describe("Path to the project directory to scan"),
1270 | operation: z
1271 | .enum(["scan", "clean", "archive"])
1272 | .describe(
1273 | "Operation: scan (detect only), clean (remove), or archive (move to .agent-archive/)",
1274 | ),
1275 | dryRun: z
1276 | .boolean()
1277 | .optional()
1278 | .default(false)
1279 | .describe("Show what would be changed without making changes"),
1280 | interactive: z
1281 | .boolean()
1282 | .optional()
1283 | .default(false)
1284 | .describe(
1285 | "Prompt for confirmation (not supported in MCP, treated as dryRun)",
1286 | ),
1287 | autoDeleteThreshold: z
1288 | .number()
1289 | .min(0)
1290 | .max(1)
1291 | .optional()
1292 | .default(0.9)
1293 | .describe("Confidence threshold for automatic deletion (0-1)"),
1294 | includeGitIgnored: z
1295 | .boolean()
1296 | .optional()
1297 | .default(false)
1298 | .describe("Include artifacts that are already in .gitignore"),
1299 | customPatterns: z
1300 | .object({
1301 | files: z.array(z.string()).optional(),
1302 | directories: z.array(z.string()).optional(),
1303 | inlineMarkers: z.array(z.string()).optional(),
1304 | })
1305 | .optional()
1306 | .describe("Custom patterns to detect in addition to defaults"),
1307 | }),
1308 | },
1309 | // Memory system tools
1310 | ...memoryTools.map((tool) => ({
1311 | ...tool,
1312 | inputSchema: z.object(
1313 | Object.entries(tool.inputSchema.properties || {}).reduce(
1314 | (acc: any, [key, value]: [string, any]) => {
1315 | if (value.type === "string") {
1316 | acc[key] = value.enum ? z.enum(value.enum) : z.string();
1317 | } else if (value.type === "number") {
1318 | acc[key] = z.number();
1319 | } else if (value.type === "boolean") {
1320 | acc[key] = z.boolean();
1321 | } else if (value.type === "object") {
1322 | acc[key] = z.object({});
1323 | }
1324 | if (value.description) {
1325 | acc[key] = acc[key].describe(value.description);
1326 | }
1327 | if (!tool.inputSchema.required?.includes(key)) {
1328 | acc[key] = acc[key].optional();
1329 | }
1330 | if (value.default !== undefined) {
1331 | acc[key] = acc[key].default(value.default);
1332 | }
1333 | return acc;
1334 | },
1335 | {},
1336 | ),
1337 | ),
1338 | })),
1339 | ];
1340 |
1341 | // Export TOOLS for use in generate_llm_context tool
1342 | export { TOOLS };
1343 |
1344 | // Set tool definitions for generate_llm_context tool
1345 | setToolDefinitions(TOOLS);
1346 |
1347 | // Native MCP Prompts for technical writing assistance
1348 | const PROMPTS = [
1349 | {
1350 | name: "tutorial-writer",
1351 | description:
1352 | "Generate learning-oriented tutorial content following Diataxis principles",
1353 | arguments: [
1354 | {
1355 | name: "project_path",
1356 | description:
1357 | "Path to the project directory (used to analyze project context)",
1358 | required: true,
1359 | },
1360 | {
1361 | name: "target_audience",
1362 | description:
1363 | "Target audience for the tutorial (default: 'beginners'). Options: 'beginners', 'intermediate', 'advanced'",
1364 | required: false,
1365 | },
1366 | {
1367 | name: "learning_goal",
1368 | description:
1369 | "What users should learn (default: 'get started with the project'). Examples: 'deploy first app', 'understand core concepts'",
1370 | required: false,
1371 | },
1372 | ],
1373 | },
1374 | {
1375 | name: "howto-guide-writer",
1376 | description:
1377 | "Generate problem-oriented how-to guide content following Diataxis principles",
1378 | arguments: [
1379 | {
1380 | name: "project_path",
1381 | description:
1382 | "Path to the project directory (used to analyze project context)",
1383 | required: true,
1384 | },
1385 | {
1386 | name: "problem",
1387 | description:
1388 | "Problem to solve (default: 'common development task'). Example: 'deploy to production', 'add authentication'",
1389 | required: false,
1390 | },
1391 | {
1392 | name: "user_experience",
1393 | description:
1394 | "User experience level (default: 'intermediate'). Options: 'beginner', 'intermediate', 'advanced'",
1395 | required: false,
1396 | },
1397 | ],
1398 | },
1399 | {
1400 | name: "reference-writer",
1401 | description:
1402 | "Generate information-oriented reference documentation following Diataxis principles",
1403 | arguments: [
1404 | {
1405 | name: "project_path",
1406 | description:
1407 | "Path to the project directory (used to analyze project context)",
1408 | required: true,
1409 | },
1410 | {
1411 | name: "reference_type",
1412 | description:
1413 | "Type of reference (default: 'API'). Options: 'API', 'CLI', 'Configuration', 'Architecture'",
1414 | required: false,
1415 | },
1416 | {
1417 | name: "completeness",
1418 | description:
1419 | "Level of completeness required (default: 'comprehensive'). Options: 'basic', 'comprehensive', 'exhaustive'",
1420 | required: false,
1421 | },
1422 | ],
1423 | },
1424 | {
1425 | name: "explanation-writer",
1426 | description:
1427 | "Generate understanding-oriented explanation content following Diataxis principles",
1428 | arguments: [
1429 | {
1430 | name: "project_path",
1431 | description:
1432 | "Path to the project directory (used to analyze project context)",
1433 | required: true,
1434 | },
1435 | {
1436 | name: "concept",
1437 | description:
1438 | "Concept to explain (default: 'system architecture'). Examples: 'data flow', 'design patterns', 'security model'",
1439 | required: false,
1440 | },
1441 | {
1442 | name: "depth",
1443 | description:
1444 | "Depth of explanation (default: 'detailed'). Options: 'overview', 'detailed', 'deep-dive'",
1445 | required: false,
1446 | },
1447 | ],
1448 | },
1449 | {
1450 | name: "diataxis-organizer",
1451 | description:
1452 | "Organize existing documentation using Diataxis framework principles",
1453 | arguments: [
1454 | {
1455 | name: "project_path",
1456 | description:
1457 | "Path to the project directory (used to analyze project context)",
1458 | required: true,
1459 | },
1460 | {
1461 | name: "current_docs",
1462 | description:
1463 | "Description of current documentation (default: 'mixed documentation'). Example: 'single README with everything', 'scattered wiki pages'",
1464 | required: false,
1465 | },
1466 | {
1467 | name: "priority",
1468 | description:
1469 | "Organization priority (default: 'user needs'). Options: 'user needs', 'completeness', 'maintainability'",
1470 | required: false,
1471 | },
1472 | ],
1473 | },
1474 | {
1475 | name: "readme-optimizer",
1476 | description: "Optimize README content using Diataxis-aware principles",
1477 | arguments: [
1478 | {
1479 | name: "project_path",
1480 | description:
1481 | "Path to the project directory (used to analyze README and project context)",
1482 | required: true,
1483 | },
1484 | {
1485 | name: "optimization_focus",
1486 | description:
1487 | "Focus area for optimization (default: 'general'). Options: 'length', 'clarity', 'structure', 'onboarding'",
1488 | required: false,
1489 | },
1490 | ],
1491 | },
1492 | // Guided workflow prompts (ADR-007)
1493 | {
1494 | name: "analyze-and-recommend",
1495 | description: "Complete repository analysis and SSG recommendation workflow",
1496 | arguments: [
1497 | {
1498 | name: "project_path",
1499 | description: "Path to the project directory (used for analysis)",
1500 | required: true,
1501 | },
1502 | {
1503 | name: "analysis_depth",
1504 | description:
1505 | "Analysis depth (default: 'standard'). Options: 'quick' (basic scan), 'standard' (comprehensive), 'deep' (detailed with dependencies)",
1506 | required: false,
1507 | },
1508 | {
1509 | name: "preferences",
1510 | description:
1511 | "SSG preferences as text (default: 'balanced approach'). Examples: 'prefer JavaScript ecosystem', 'prioritize simplicity', 'need fast builds'",
1512 | required: false,
1513 | },
1514 | ],
1515 | },
1516 | {
1517 | name: "setup-documentation",
1518 | description:
1519 | "Create comprehensive documentation structure with best practices",
1520 | arguments: [
1521 | {
1522 | name: "project_path",
1523 | description:
1524 | "Path to the project directory (where docs will be created)",
1525 | required: true,
1526 | },
1527 | {
1528 | name: "ssg_type",
1529 | description:
1530 | "Static site generator type (default: 'recommended based on analysis'). Options: 'jekyll', 'hugo', 'docusaurus', 'mkdocs', 'eleventy'",
1531 | required: false,
1532 | },
1533 | {
1534 | name: "include_examples",
1535 | description:
1536 | "Include example content (default: 'true'). Set to 'false' for templates only, 'true' for populated examples",
1537 | required: false,
1538 | },
1539 | ],
1540 | },
1541 | {
1542 | name: "troubleshoot-deployment",
1543 | description: "Diagnose and fix GitHub Pages deployment issues",
1544 | arguments: [
1545 | {
1546 | name: "repository",
1547 | description:
1548 | "Repository path or URL (GitHub repository to troubleshoot)",
1549 | required: true,
1550 | },
1551 | {
1552 | name: "deployment_url",
1553 | description:
1554 | "Expected deployment URL (default: derived from repository). Example: 'https://username.github.io/repo'",
1555 | required: false,
1556 | },
1557 | {
1558 | name: "issue_description",
1559 | description:
1560 | "Description of the issue (default: 'deployment not working'). Examples: 'builds fail', '404 errors', 'outdated content'",
1561 | required: false,
1562 | },
1563 | ],
1564 | },
1565 | {
1566 | name: "maintain-documentation-freshness",
1567 | description:
1568 | "Track and maintain documentation freshness with automated staleness detection",
1569 | arguments: [
1570 | {
1571 | name: "project_path",
1572 | description:
1573 | "Path to the project directory (used for knowledge graph tracking)",
1574 | required: true,
1575 | },
1576 | {
1577 | name: "docs_path",
1578 | description:
1579 | "Path to documentation directory (default: derived from project). Example: './docs', './documentation'",
1580 | required: false,
1581 | },
1582 | {
1583 | name: "freshness_preset",
1584 | description:
1585 | "Staleness threshold preset (default: 'monthly'). Options: 'realtime' (minutes), 'active' (hours), 'recent' (days), 'weekly' (7 days), 'monthly' (30 days), 'quarterly' (90 days)",
1586 | required: false,
1587 | },
1588 | {
1589 | name: "action",
1590 | description:
1591 | "Action to perform (default: 'track'). Options: 'validate' (initialize metadata), 'track' (scan staleness), 'insights' (view trends)",
1592 | required: false,
1593 | },
1594 | ],
1595 | },
1596 | // Code Mode Orchestration Prompts (ADR-011: CE-MCP Compatibility)
1597 | // These prompts guide LLMs to write efficient orchestration code
1598 | {
1599 | name: "code-mode-documentation-setup",
1600 | description:
1601 | "Complete documentation setup using code-based orchestration (Code Mode optimized)",
1602 | arguments: [
1603 | {
1604 | name: "project_path",
1605 | description: "Path to the project directory",
1606 | required: true,
1607 | },
1608 | {
1609 | name: "ssg_preference",
1610 | description:
1611 | "SSG preference (default: 'auto-detect'). Options: 'auto-detect', 'jekyll', 'hugo', 'docusaurus', 'mkdocs', 'eleventy'",
1612 | required: false,
1613 | },
1614 | {
1615 | name: "include_deployment",
1616 | description: "Include GitHub Pages deployment setup (default: 'true')",
1617 | required: false,
1618 | },
1619 | ],
1620 | },
1621 | {
1622 | name: "code-mode-parallel-workflow",
1623 | description:
1624 | "Execute multiple documcp operations in parallel for maximum efficiency (Code Mode optimized)",
1625 | arguments: [
1626 | {
1627 | name: "project_path",
1628 | description: "Path to the project directory",
1629 | required: true,
1630 | },
1631 | {
1632 | name: "operations",
1633 | description:
1634 | "Comma-separated operations to run in parallel (default: 'analysis,validation,freshness'). Options: 'analysis', 'validation', 'freshness', 'gap-detection', 'link-checking'",
1635 | required: false,
1636 | },
1637 | ],
1638 | },
1639 | {
1640 | name: "code-mode-efficient-analysis",
1641 | description:
1642 | "Comprehensive project analysis with resource-based result filtering (Code Mode optimized)",
1643 | arguments: [
1644 | {
1645 | name: "project_path",
1646 | description: "Path to the project directory",
1647 | required: true,
1648 | },
1649 | {
1650 | name: "include_recommendations",
1651 | description: "Include immediate SSG recommendations (default: 'true')",
1652 | required: false,
1653 | },
1654 | ],
1655 | },
1656 | ];
1657 |
1658 | // MCP resources should serve APPLICATION needs, not store tool results
1659 | // Resources are app-controlled and used for UI display, autocomplete, etc.
1660 |
1661 | // Resource definitions following ADR-007 and MCP best practices
1662 | // Resources serve APPLICATIONS (UI needs) not tool result storage
1663 | const RESOURCES = [
1664 | // Static Site Generators - for UI selection dropdowns
1665 | {
1666 | uri: "documcp://ssgs/available",
1667 | name: "Available Static Site Generators",
1668 | description: "List of supported SSGs with capabilities for UI selection",
1669 | mimeType: "application/json",
1670 | },
1671 | // Templates - static templates for documentation setup
1672 | {
1673 | uri: "documcp://templates/jekyll-config",
1674 | name: "Jekyll Configuration Template",
1675 | description: "Template for Jekyll _config.yml",
1676 | mimeType: "text/yaml",
1677 | },
1678 | {
1679 | uri: "documcp://templates/hugo-config",
1680 | name: "Hugo Configuration Template",
1681 | description: "Template for Hugo config.yaml",
1682 | mimeType: "text/yaml",
1683 | },
1684 | {
1685 | uri: "documcp://templates/docusaurus-config",
1686 | name: "Docusaurus Configuration Template",
1687 | description: "Template for Docusaurus docusaurus.config.js",
1688 | mimeType: "text/javascript",
1689 | },
1690 | {
1691 | uri: "documcp://templates/mkdocs-config",
1692 | name: "MkDocs Configuration Template",
1693 | description: "Template for MkDocs mkdocs.yml",
1694 | mimeType: "text/yaml",
1695 | },
1696 | {
1697 | uri: "documcp://templates/eleventy-config",
1698 | name: "Eleventy Configuration Template",
1699 | description: "Template for Eleventy .eleventy.js",
1700 | mimeType: "text/javascript",
1701 | },
1702 | {
1703 | uri: "documcp://templates/diataxis-structure",
1704 | name: "Diataxis Structure Template",
1705 | description: "Diataxis documentation structure blueprint",
1706 | mimeType: "application/json",
1707 | },
1708 | // Workflows - for UI to display available workflows
1709 | {
1710 | uri: "documcp://workflows/all",
1711 | name: "All Documentation Workflows",
1712 | description: "Complete list of available documentation workflows",
1713 | mimeType: "application/json",
1714 | },
1715 | {
1716 | uri: "documcp://workflows/quick-setup",
1717 | name: "Quick Documentation Setup Workflow",
1718 | description: "Fast-track workflow for basic documentation",
1719 | mimeType: "application/json",
1720 | },
1721 | {
1722 | uri: "documcp://workflows/full-setup",
1723 | name: "Full Documentation Setup Workflow",
1724 | description: "Comprehensive workflow for complete documentation",
1725 | mimeType: "application/json",
1726 | },
1727 | {
1728 | uri: "documcp://workflows/guidance",
1729 | name: "Workflow Execution Guidance",
1730 | description: "Guidelines for executing documentation workflows",
1731 | mimeType: "application/json",
1732 | },
1733 | // Freshness tracking - for UI selection and configuration
1734 | {
1735 | uri: "documcp://freshness/presets",
1736 | name: "Documentation Freshness Presets",
1737 | description:
1738 | "Available staleness threshold presets for UI selection (realtime, active, recent, weekly, monthly, quarterly)",
1739 | mimeType: "application/json",
1740 | },
1741 | {
1742 | uri: "documcp://freshness/metadata-schema",
1743 | name: "Freshness Metadata Schema",
1744 | description:
1745 | "Schema for documentation frontmatter freshness metadata fields",
1746 | mimeType: "application/json",
1747 | },
1748 | ];
1749 |
1750 | // List available tools
1751 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
1752 | tools: TOOLS.map((tool) => ({
1753 | name: tool.name,
1754 | description: tool.description,
1755 | inputSchema: zodToJsonSchema(tool.inputSchema),
1756 | })),
1757 | }));
1758 |
1759 | // Helper function to detect documentation directories
1760 | async function detectDocsDirectories(
1761 | projectRoot: string,
1762 | ): Promise<Array<{ path: string; name: string }>> {
1763 | const commonDocsDirs = [
1764 | "docs",
1765 | "documentation",
1766 | "doc",
1767 | "wiki",
1768 | "website/docs", // Docusaurus pattern
1769 | ".vitepress", // VitePress
1770 | "book", // mdBook
1771 | ];
1772 |
1773 | const detected: Array<{ path: string; name: string }> = [];
1774 |
1775 | for (const dirName of commonDocsDirs) {
1776 | const fullPath = path.join(projectRoot, dirName);
1777 | try {
1778 | const stats = await fs.stat(fullPath);
1779 | if (stats.isDirectory()) {
1780 | detected.push({
1781 | path: fullPath,
1782 | name: dirName,
1783 | });
1784 | }
1785 | } catch {
1786 | // Directory doesn't exist, skip
1787 | }
1788 | }
1789 |
1790 | return detected;
1791 | }
1792 |
1793 | // List allowed roots (includes auto-detected docs directories)
1794 | server.setRequestHandler(ListRootsRequestSchema, async () => {
1795 | const roots: Array<{
1796 | uri: string;
1797 | name: string;
1798 | type?: string;
1799 | description?: string;
1800 | parent?: string;
1801 | }> = [];
1802 |
1803 | // Add project roots
1804 | for (const root of allowedRoots) {
1805 | roots.push({
1806 | uri: `file://${root}`,
1807 | name: path.basename(root),
1808 | type: "project",
1809 | description: "Project root containing source code and documentation",
1810 | });
1811 |
1812 | // Auto-detect and add docs directories within this root
1813 | const docsDirectories = await detectDocsDirectories(root);
1814 | for (const docsDir of docsDirectories) {
1815 | roots.push({
1816 | uri: `file://${docsDir.path}`,
1817 | name: docsDir.name,
1818 | type: "documentation",
1819 | description: `Documentation directory within ${path.basename(root)}`,
1820 | parent: `file://${root}`,
1821 | });
1822 | }
1823 | }
1824 |
1825 | return { roots };
1826 | });
1827 |
1828 | // List available prompts
1829 | server.setRequestHandler(ListPromptsRequestSchema, async () => ({
1830 | prompts: PROMPTS,
1831 | }));
1832 |
1833 | // Get specific prompt
1834 | server.setRequestHandler(GetPromptRequestSchema, async (request) => {
1835 | const { name, arguments: args } = request.params;
1836 |
1837 | // Handle Code Mode orchestration prompts (ADR-011)
1838 | if (name.startsWith("code-mode-")) {
1839 | const projectPath = args?.project_path || process.cwd();
1840 | return generateCodeModePrompt(name, projectPath, args || {});
1841 | }
1842 |
1843 | // Generate dynamic prompt messages using our Diataxis-aligned prompt system
1844 | const projectPath = args?.project_path || process.cwd();
1845 | const messages = await generateTechnicalWriterPrompts(
1846 | name,
1847 | projectPath,
1848 | args || {},
1849 | );
1850 |
1851 | return {
1852 | description: `Technical writing assistance for ${name}`,
1853 | messages,
1854 | };
1855 | });
1856 |
1857 | // List available resources
1858 | server.setRequestHandler(ListResourcesRequestSchema, async () => ({
1859 | resources: RESOURCES,
1860 | }));
1861 |
1862 | // Read specific resource
1863 | // Resources serve APPLICATION needs - static content for UI display
1864 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1865 | const { uri } = request.params;
1866 |
1867 | // Handle SSG list resource (for UI dropdowns/selection)
1868 | if (uri === "documcp://ssgs/available") {
1869 | return {
1870 | contents: [
1871 | {
1872 | uri,
1873 | mimeType: "application/json",
1874 | text: JSON.stringify(
1875 | {
1876 | ssgs: [
1877 | {
1878 | id: "jekyll",
1879 | name: "Jekyll",
1880 | description: "Ruby-based SSG, great for GitHub Pages",
1881 | language: "ruby",
1882 | complexity: "low",
1883 | buildSpeed: "medium",
1884 | ecosystem: "mature",
1885 | bestFor: ["blogs", "documentation", "simple-sites"],
1886 | },
1887 | {
1888 | id: "hugo",
1889 | name: "Hugo",
1890 | description: "Go-based SSG, extremely fast builds",
1891 | language: "go",
1892 | complexity: "medium",
1893 | buildSpeed: "very-fast",
1894 | ecosystem: "mature",
1895 | bestFor: ["documentation", "blogs", "large-sites"],
1896 | },
1897 | {
1898 | id: "docusaurus",
1899 | name: "Docusaurus",
1900 | description:
1901 | "React-based, optimized for technical documentation",
1902 | language: "javascript",
1903 | complexity: "medium",
1904 | buildSpeed: "medium",
1905 | ecosystem: "growing",
1906 | bestFor: [
1907 | "technical-documentation",
1908 | "api-docs",
1909 | "versioned-docs",
1910 | ],
1911 | },
1912 | {
1913 | id: "mkdocs",
1914 | name: "MkDocs",
1915 | description: "Python-based, simple and fast documentation",
1916 | language: "python",
1917 | complexity: "low",
1918 | buildSpeed: "fast",
1919 | ecosystem: "mature",
1920 | bestFor: ["documentation", "technical-docs", "simple-setup"],
1921 | },
1922 | {
1923 | id: "eleventy",
1924 | name: "Eleventy",
1925 | description: "JavaScript-based, simple and flexible",
1926 | language: "javascript",
1927 | complexity: "low",
1928 | buildSpeed: "fast",
1929 | ecosystem: "growing",
1930 | bestFor: ["blogs", "documentation", "flexible-sites"],
1931 | },
1932 | ],
1933 | },
1934 | null,
1935 | 2,
1936 | ),
1937 | },
1938 | ],
1939 | };
1940 | }
1941 |
1942 | // Handle template resources (static content)
1943 | if (uri.startsWith("documcp://templates/")) {
1944 | const templateType = uri.split("/").pop();
1945 |
1946 | switch (templateType) {
1947 | case "jekyll-config":
1948 | return {
1949 | contents: [
1950 | {
1951 | uri,
1952 | mimeType: "text/yaml",
1953 | text: `# Jekyll Configuration Template
1954 | title: "Documentation Site"
1955 | description: "Project documentation"
1956 | baseurl: ""
1957 | url: ""
1958 |
1959 | markdown: kramdown
1960 | highlighter: rouge
1961 | theme: minima
1962 |
1963 | plugins:
1964 | - jekyll-feed
1965 | - jekyll-sitemap
1966 |
1967 | exclude:
1968 | - Gemfile
1969 | - Gemfile.lock
1970 | - node_modules
1971 | - vendor
1972 | `,
1973 | },
1974 | ],
1975 | };
1976 |
1977 | case "hugo-config":
1978 | return {
1979 | contents: [
1980 | {
1981 | uri,
1982 | mimeType: "text/yaml",
1983 | text: `# Hugo Configuration Template
1984 | baseURL: "https://username.github.io/repository"
1985 | languageCode: "en-us"
1986 | title: "Documentation Site"
1987 | theme: "docsy"
1988 |
1989 | params:
1990 | github_repo: "https://github.com/username/repository"
1991 | github_branch: "main"
1992 |
1993 | markup:
1994 | goldmark:
1995 | renderer:
1996 | unsafe: true
1997 | highlight:
1998 | style: github
1999 | lineNos: true
2000 | `,
2001 | },
2002 | ],
2003 | };
2004 |
2005 | case "docusaurus-config":
2006 | return {
2007 | contents: [
2008 | {
2009 | uri,
2010 | mimeType: "text/javascript",
2011 | text: `// Docusaurus Configuration Template
2012 | // @ts-check
2013 |
2014 | /** @type {import('@docusaurus/types').Config} */
2015 | const config = {
2016 | title: 'Documentation Site',
2017 | tagline: 'Project documentation',
2018 | url: 'https://username.github.io',
2019 | baseUrl: '/repository/',
2020 | onBrokenLinks: 'throw',
2021 | onBrokenMarkdownLinks: 'warn',
2022 | favicon: 'img/favicon.ico',
2023 |
2024 | organizationName: 'username',
2025 | projectName: 'repository',
2026 |
2027 | i18n: {
2028 | defaultLocale: 'en',
2029 | locales: ['en'],
2030 | },
2031 |
2032 | presets: [
2033 | [
2034 | 'classic',
2035 | /** @type {import('@docusaurus/preset-classic').Options} */
2036 | ({
2037 | docs: {
2038 | sidebarPath: require.resolve('./sidebars.js'),
2039 | editUrl: 'https://github.com/username/repository/tree/main/',
2040 | },
2041 | blog: false,
2042 | theme: {
2043 | customCss: require.resolve('./src/css/custom.css'),
2044 | },
2045 | }),
2046 | ],
2047 | ],
2048 |
2049 | themeConfig:
2050 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
2051 | ({
2052 | navbar: {
2053 | title: 'Documentation',
2054 | items: [
2055 | {
2056 | type: 'doc',
2057 | docId: 'intro',
2058 | position: 'left',
2059 | label: 'Tutorial',
2060 | },
2061 | {
2062 | href: 'https://github.com/username/repository',
2063 | label: 'GitHub',
2064 | position: 'right',
2065 | },
2066 | ],
2067 | },
2068 | footer: {
2069 | style: 'dark',
2070 | copyright: \`Copyright © \${new Date().getFullYear()} Project Name\`,
2071 | },
2072 | }),
2073 | };
2074 |
2075 | module.exports = config;
2076 | `,
2077 | },
2078 | ],
2079 | };
2080 |
2081 | case "mkdocs-config":
2082 | return {
2083 | contents: [
2084 | {
2085 | uri,
2086 | mimeType: "text/yaml",
2087 | text: `# MkDocs Configuration Template
2088 | site_name: Documentation Site
2089 | site_url: https://username.github.io/repository
2090 | repo_url: https://github.com/username/repository
2091 | repo_name: username/repository
2092 |
2093 | theme:
2094 | name: material
2095 | palette:
2096 | - scheme: default
2097 | primary: indigo
2098 | accent: indigo
2099 | toggle:
2100 | icon: material/brightness-7
2101 | name: Switch to dark mode
2102 | - scheme: slate
2103 | primary: indigo
2104 | accent: indigo
2105 | toggle:
2106 | icon: material/brightness-4
2107 | name: Switch to light mode
2108 | features:
2109 | - navigation.tabs
2110 | - navigation.sections
2111 | - toc.integrate
2112 | - navigation.top
2113 | - search.suggest
2114 | - search.highlight
2115 | - content.tabs.link
2116 |
2117 | plugins:
2118 | - search
2119 | - awesome-pages
2120 |
2121 | markdown_extensions:
2122 | - pymdownx.highlight
2123 | - pymdownx.superfences
2124 | - pymdownx.tabbed
2125 | - admonition
2126 | - pymdownx.details
2127 |
2128 | nav:
2129 | - Home: index.md
2130 | - Tutorials: tutorials/
2131 | - How-To Guides: how-to/
2132 | - Reference: reference/
2133 | - Explanation: explanation/
2134 | `,
2135 | },
2136 | ],
2137 | };
2138 |
2139 | case "eleventy-config":
2140 | return {
2141 | contents: [
2142 | {
2143 | uri,
2144 | mimeType: "text/javascript",
2145 | text: `// Eleventy Configuration Template
2146 | module.exports = function(eleventyConfig) {
2147 | // Copy static assets
2148 | eleventyConfig.addPassthroughCopy("src/css");
2149 | eleventyConfig.addPassthroughCopy("src/js");
2150 | eleventyConfig.addPassthroughCopy("src/images");
2151 |
2152 | // Add plugins
2153 | // eleventyConfig.addPlugin(require("@11ty/eleventy-plugin-syntaxhighlight"));
2154 |
2155 | // Add filters
2156 | eleventyConfig.addFilter("readableDate", dateObj => {
2157 | return new Date(dateObj).toLocaleDateString();
2158 | });
2159 |
2160 | // Add shortcodes
2161 | eleventyConfig.addShortcode("year", () => \`\${new Date().getFullYear()}\`);
2162 |
2163 | // Markdown configuration
2164 | let markdownIt = require("markdown-it");
2165 | let markdownItAnchor = require("markdown-it-anchor");
2166 | let options = {
2167 | html: true,
2168 | breaks: true,
2169 | linkify: true
2170 | };
2171 |
2172 | eleventyConfig.setLibrary("md", markdownIt(options)
2173 | .use(markdownItAnchor)
2174 | );
2175 |
2176 | return {
2177 | dir: {
2178 | input: "src",
2179 | output: "_site",
2180 | includes: "_includes",
2181 | layouts: "_layouts",
2182 | data: "_data"
2183 | },
2184 | templateFormats: ["md", "njk", "html"],
2185 | markdownTemplateEngine: "njk",
2186 | htmlTemplateEngine: "njk",
2187 | dataTemplateEngine: "njk"
2188 | };
2189 | };
2190 | `,
2191 | },
2192 | ],
2193 | };
2194 |
2195 | case "diataxis-structure":
2196 | return {
2197 | contents: [
2198 | {
2199 | uri,
2200 | mimeType: "application/json",
2201 | text: JSON.stringify(
2202 | {
2203 | structure: {
2204 | tutorials: {
2205 | description: "Learning-oriented guides",
2206 | files: ["getting-started.md", "your-first-project.md"],
2207 | },
2208 | "how-to-guides": {
2209 | description: "Problem-oriented step-by-step guides",
2210 | files: ["common-tasks.md", "troubleshooting.md"],
2211 | },
2212 | reference: {
2213 | description: "Information-oriented technical reference",
2214 | files: ["api-reference.md", "configuration.md"],
2215 | },
2216 | explanation: {
2217 | description: "Understanding-oriented background material",
2218 | files: ["architecture.md", "design-decisions.md"],
2219 | },
2220 | },
2221 | },
2222 | null,
2223 | 2,
2224 | ),
2225 | },
2226 | ],
2227 | };
2228 |
2229 | default:
2230 | throw new Error(`Unknown template: ${templateType}`);
2231 | }
2232 | }
2233 |
2234 | // Handle workflow resources
2235 | if (uri.startsWith("documcp://workflows/")) {
2236 | const workflowType = uri.split("/").pop();
2237 |
2238 | switch (workflowType) {
2239 | case "all":
2240 | return {
2241 | contents: [
2242 | {
2243 | uri,
2244 | mimeType: "application/json",
2245 | text: JSON.stringify(
2246 | {
2247 | workflows: DOCUMENTATION_WORKFLOWS,
2248 | executionGuidance: WORKFLOW_EXECUTION_GUIDANCE,
2249 | metadata: WORKFLOW_METADATA,
2250 | },
2251 | null,
2252 | 2,
2253 | ),
2254 | },
2255 | ],
2256 | };
2257 |
2258 | case "quick-setup":
2259 | return {
2260 | contents: [
2261 | {
2262 | uri,
2263 | mimeType: "application/json",
2264 | text: JSON.stringify(
2265 | DOCUMENTATION_WORKFLOWS["quick-documentation-setup"],
2266 | null,
2267 | 2,
2268 | ),
2269 | },
2270 | ],
2271 | };
2272 |
2273 | case "full-setup":
2274 | return {
2275 | contents: [
2276 | {
2277 | uri,
2278 | mimeType: "application/json",
2279 | text: JSON.stringify(
2280 | DOCUMENTATION_WORKFLOWS["full-documentation-setup"],
2281 | null,
2282 | 2,
2283 | ),
2284 | },
2285 | ],
2286 | };
2287 |
2288 | case "guidance":
2289 | return {
2290 | contents: [
2291 | {
2292 | uri,
2293 | mimeType: "application/json",
2294 | text: JSON.stringify(
2295 | {
2296 | executionGuidance: WORKFLOW_EXECUTION_GUIDANCE,
2297 | recommendationEngine:
2298 | "Use recommendWorkflow() function with project status and requirements",
2299 | },
2300 | null,
2301 | 2,
2302 | ),
2303 | },
2304 | ],
2305 | };
2306 |
2307 | default: {
2308 | // Try to find specific workflow
2309 | const workflow = DOCUMENTATION_WORKFLOWS[workflowType || ""];
2310 | if (workflow) {
2311 | return {
2312 | contents: [
2313 | {
2314 | uri,
2315 | mimeType: "application/json",
2316 | text: JSON.stringify(workflow, null, 2),
2317 | },
2318 | ],
2319 | };
2320 | }
2321 | throw new Error(`Unknown workflow: ${workflowType}`);
2322 | }
2323 | }
2324 | }
2325 |
2326 | // Handle freshness tracking resources
2327 | if (uri.startsWith("documcp://freshness/")) {
2328 | const freshnessType = uri.split("/").pop();
2329 |
2330 | switch (freshnessType) {
2331 | case "presets":
2332 | return {
2333 | contents: [
2334 | {
2335 | uri,
2336 | mimeType: "application/json",
2337 | text: JSON.stringify(
2338 | {
2339 | presets: [
2340 | {
2341 | id: "realtime",
2342 | name: "Realtime",
2343 | description:
2344 | "For frequently updated documentation (minutes)",
2345 | thresholds: {
2346 | warning: { value: 5, unit: "minutes" },
2347 | stale: { value: 15, unit: "minutes" },
2348 | critical: { value: 30, unit: "minutes" },
2349 | },
2350 | bestFor: ["api-docs", "status-pages", "live-updates"],
2351 | },
2352 | {
2353 | id: "active",
2354 | name: "Active",
2355 | description:
2356 | "For actively maintained documentation (hours)",
2357 | thresholds: {
2358 | warning: { value: 2, unit: "hours" },
2359 | stale: { value: 6, unit: "hours" },
2360 | critical: { value: 12, unit: "hours" },
2361 | },
2362 | bestFor: [
2363 | "development-docs",
2364 | "feature-guides",
2365 | "release-notes",
2366 | ],
2367 | },
2368 | {
2369 | id: "recent",
2370 | name: "Recent",
2371 | description: "For regularly updated documentation (days)",
2372 | thresholds: {
2373 | warning: { value: 1, unit: "days" },
2374 | stale: { value: 3, unit: "days" },
2375 | critical: { value: 7, unit: "days" },
2376 | },
2377 | bestFor: [
2378 | "tutorials",
2379 | "getting-started",
2380 | "project-updates",
2381 | ],
2382 | },
2383 | {
2384 | id: "weekly",
2385 | name: "Weekly",
2386 | description: "For weekly maintenance cycle (7 days)",
2387 | thresholds: {
2388 | warning: { value: 7, unit: "days" },
2389 | stale: { value: 14, unit: "days" },
2390 | critical: { value: 30, unit: "days" },
2391 | },
2392 | bestFor: ["how-to-guides", "examples", "best-practices"],
2393 | },
2394 | {
2395 | id: "monthly",
2396 | name: "Monthly",
2397 | description:
2398 | "For monthly maintenance cycle (30 days) - DEFAULT",
2399 | thresholds: {
2400 | warning: { value: 30, unit: "days" },
2401 | stale: { value: 60, unit: "days" },
2402 | critical: { value: 90, unit: "days" },
2403 | },
2404 | bestFor: [
2405 | "reference-docs",
2406 | "architecture",
2407 | "stable-features",
2408 | ],
2409 | default: true,
2410 | },
2411 | {
2412 | id: "quarterly",
2413 | name: "Quarterly",
2414 | description: "For quarterly maintenance cycle (90 days)",
2415 | thresholds: {
2416 | warning: { value: 90, unit: "days" },
2417 | stale: { value: 180, unit: "days" },
2418 | critical: { value: 365, unit: "days" },
2419 | },
2420 | bestFor: [
2421 | "explanations",
2422 | "background",
2423 | "rarely-changing-docs",
2424 | ],
2425 | },
2426 | ],
2427 | },
2428 | null,
2429 | 2,
2430 | ),
2431 | },
2432 | ],
2433 | };
2434 |
2435 | case "metadata-schema":
2436 | return {
2437 | contents: [
2438 | {
2439 | uri,
2440 | mimeType: "application/json",
2441 | text: JSON.stringify(
2442 | {
2443 | schema: {
2444 | documcp: {
2445 | description: "DocuMCP metadata block in YAML frontmatter",
2446 | type: "object",
2447 | properties: {
2448 | last_updated: {
2449 | type: "string",
2450 | format: "date-time",
2451 | description:
2452 | "ISO 8601 timestamp of last content update",
2453 | example: "2025-01-19T10:30:00Z",
2454 | },
2455 | last_validated: {
2456 | type: "string",
2457 | format: "date-time",
2458 | description:
2459 | "ISO 8601 timestamp of last validation check",
2460 | example: "2025-01-19T10:30:00Z",
2461 | },
2462 | update_frequency: {
2463 | type: "string",
2464 | enum: [
2465 | "realtime",
2466 | "active",
2467 | "recent",
2468 | "weekly",
2469 | "monthly",
2470 | "quarterly",
2471 | ],
2472 | description: "Expected update frequency preset",
2473 | default: "monthly",
2474 | },
2475 | validated_against_commit: {
2476 | type: "string",
2477 | description:
2478 | "Git commit hash the documentation was validated against",
2479 | example: "a1b2c3d",
2480 | },
2481 | auto_updated: {
2482 | type: "boolean",
2483 | description:
2484 | "Whether timestamps are automatically updated",
2485 | default: false,
2486 | },
2487 | },
2488 | required: ["last_updated"],
2489 | },
2490 | },
2491 | example: {
2492 | yaml: `---
2493 | title: "API Reference"
2494 | description: "Complete API documentation"
2495 | documcp:
2496 | last_updated: "2025-01-19T10:30:00Z"
2497 | last_validated: "2025-01-19T10:30:00Z"
2498 | update_frequency: "monthly"
2499 | validated_against_commit: "a1b2c3d"
2500 | auto_updated: false
2501 | ---`,
2502 | },
2503 | },
2504 | null,
2505 | 2,
2506 | ),
2507 | },
2508 | ],
2509 | };
2510 |
2511 | default:
2512 | throw new Error(`Unknown freshness resource: ${freshnessType}`);
2513 | }
2514 | }
2515 |
2516 | throw new Error(`Resource not found: ${uri}`);
2517 | });
2518 |
2519 | // Helper to wrap tool results in standard MCP format
2520 | function wrapToolResult<T>(result: T, _toolName: string) {
2521 | // If result is already in MCP format (has 'content' array), return as-is
2522 | if (
2523 | result &&
2524 | typeof result === "object" &&
2525 | "content" in result &&
2526 | Array.isArray((result as any).content)
2527 | ) {
2528 | return result;
2529 | }
2530 |
2531 | // Otherwise, wrap in formatMCPResponse
2532 | return formatMCPResponse({
2533 | success: true,
2534 | data: result,
2535 | metadata: {
2536 | toolVersion: packageJson.version,
2537 | executionTime: Date.now(),
2538 | timestamp: new Date().toISOString(),
2539 | },
2540 | });
2541 | }
2542 |
2543 | // Handle tool execution
2544 | server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
2545 | const { name, arguments: args } = request.params;
2546 |
2547 | try {
2548 | switch (name) {
2549 | case "analyze_repository": {
2550 | // Check if path is allowed
2551 | const repoPath = (args as any)?.path;
2552 | if (repoPath && !isPathAllowed(repoPath, allowedRoots)) {
2553 | return formatMCPResponse({
2554 | success: false,
2555 | error: {
2556 | code: "PERMISSION_DENIED",
2557 | message: getPermissionDeniedMessage(repoPath, allowedRoots),
2558 | resolution:
2559 | "Request access to this directory by starting the server with --root argument, or use a path within allowed roots.",
2560 | },
2561 | metadata: {
2562 | toolVersion: packageJson.version,
2563 | executionTime: 0,
2564 | timestamp: new Date().toISOString(),
2565 | },
2566 | });
2567 | }
2568 |
2569 | const result = await analyzeRepository(args, extra);
2570 |
2571 | // Remember in persistent memory
2572 | if (args?.path && typeof args.path === "string") {
2573 | const memoryId = await rememberAnalysis(args.path, result);
2574 | (result as any).memoryId = memoryId;
2575 |
2576 | // Get insights from similar projects
2577 | const similarProjects = await getSimilarProjects(result, 3);
2578 | if (similarProjects.length > 0) {
2579 | (result as any).insights = {
2580 | similarProjects,
2581 | message: `Found ${similarProjects.length} similar projects in memory`,
2582 | };
2583 | }
2584 | }
2585 |
2586 | return wrapToolResult(result, "analyze_repository");
2587 | }
2588 |
2589 | case "recommend_ssg": {
2590 | const result = await recommendSSG(args, extra);
2591 |
2592 | // Remember recommendation
2593 | if (args?.analysisId && typeof args.analysisId === "string") {
2594 | const memoryId = await rememberRecommendation(
2595 | args.analysisId,
2596 | result,
2597 | );
2598 | (result as any).memoryId = memoryId;
2599 |
2600 | // Get project history if available
2601 | const projectInsights = await getProjectInsights(args.analysisId);
2602 | if (projectInsights.length > 0) {
2603 | (result as any).projectHistory = projectInsights;
2604 | }
2605 | }
2606 | return wrapToolResult(result, "recommend_ssg");
2607 | }
2608 |
2609 | case "generate_config": {
2610 | const result = await generateConfig(args);
2611 | return wrapToolResult(result, "generate_config");
2612 | }
2613 |
2614 | case "setup_structure": {
2615 | // Check if basePath is allowed
2616 | const basePath = (args as any)?.basePath;
2617 | if (basePath && !isPathAllowed(basePath, allowedRoots)) {
2618 | return formatMCPResponse({
2619 | success: false,
2620 | error: {
2621 | code: "PERMISSION_DENIED",
2622 | message: getPermissionDeniedMessage(basePath, allowedRoots),
2623 | resolution:
2624 | "Request access to this directory by starting the server with --root argument.",
2625 | },
2626 | metadata: {
2627 | toolVersion: packageJson.version,
2628 | executionTime: 0,
2629 | timestamp: new Date().toISOString(),
2630 | },
2631 | });
2632 | }
2633 |
2634 | const result = await setupStructure(args);
2635 | return wrapToolResult(result, "setup_structure");
2636 | }
2637 |
2638 | case "setup_playwright_tests": {
2639 | const result = await setupPlaywrightTests(args);
2640 | return wrapToolResult(result, "setup_playwright_tests");
2641 | }
2642 |
2643 | case "deploy_pages": {
2644 | const result = await deployPages(args, extra);
2645 | return wrapToolResult(result, "deploy_pages");
2646 | }
2647 |
2648 | case "verify_deployment": {
2649 | const result = await verifyDeployment(args);
2650 | return wrapToolResult(result, "verify_deployment");
2651 | }
2652 |
2653 | case "populate_diataxis_content": {
2654 | // Check if docsPath is allowed
2655 | const docsPath = (args as any)?.docsPath;
2656 | if (docsPath && !isPathAllowed(docsPath, allowedRoots)) {
2657 | return formatMCPResponse({
2658 | success: false,
2659 | error: {
2660 | code: "PERMISSION_DENIED",
2661 | message: getPermissionDeniedMessage(docsPath, allowedRoots),
2662 | resolution:
2663 | "Request access to this directory by starting the server with --root argument.",
2664 | },
2665 | metadata: {
2666 | toolVersion: packageJson.version,
2667 | executionTime: 0,
2668 | timestamp: new Date().toISOString(),
2669 | },
2670 | });
2671 | }
2672 |
2673 | const result = await handlePopulateDiataxisContent(args, extra);
2674 | return {
2675 | content: [
2676 | {
2677 | type: "text",
2678 | text: `Content population completed successfully. Generated ${
2679 | result.filesCreated
2680 | } files with ${Math.round(
2681 | result.populationMetrics.coverage,
2682 | )}% coverage.`,
2683 | },
2684 | {
2685 | type: "text",
2686 | text: `Population metrics: Coverage: ${result.populationMetrics.coverage}%, Completeness: ${result.populationMetrics.completeness}%, Project Specificity: ${result.populationMetrics.projectSpecificity}%`,
2687 | },
2688 | {
2689 | type: "text",
2690 | text: `Next steps:\n${result.nextSteps
2691 | .map((step) => `- ${step}`)
2692 | .join("\n")}`,
2693 | },
2694 | ],
2695 | };
2696 | }
2697 |
2698 | case "update_existing_documentation": {
2699 | const result = await handleUpdateExistingDocumentation(args);
2700 | return {
2701 | content: [
2702 | {
2703 | type: "text",
2704 | text: `Documentation analysis completed. Found ${result.updateMetrics.gapsDetected} gaps and generated ${result.updateMetrics.recommendationsGenerated} recommendations.`,
2705 | },
2706 | {
2707 | type: "text",
2708 | text: `Update metrics: Confidence Score: ${result.updateMetrics.confidenceScore}, Estimated Effort: ${result.updateMetrics.estimatedEffort}`,
2709 | },
2710 | {
2711 | type: "text",
2712 | text: `Memory insights: ${result.memoryInsights.similarProjects.length} similar projects analyzed, ${result.memoryInsights.successfulUpdatePatterns.length} successful update patterns found`,
2713 | },
2714 | {
2715 | type: "text",
2716 | text: `Top recommendations:\n${result.recommendations
2717 | .slice(0, 5)
2718 | .map(
2719 | (rec, i) =>
2720 | `${i + 1}. ${rec.reasoning} (confidence: ${Math.round(
2721 | rec.confidence * 100,
2722 | )}%)`,
2723 | )
2724 | .join("\n")}`,
2725 | },
2726 | {
2727 | type: "text",
2728 | text: `Next steps:\n${result.nextSteps
2729 | .map((step) => `- ${step}`)
2730 | .join("\n")}`,
2731 | },
2732 | ],
2733 | };
2734 | }
2735 |
2736 | case "validate_diataxis_content": {
2737 | // Check if contentPath is allowed
2738 | const contentPath = (args as any)?.contentPath;
2739 | if (contentPath && !isPathAllowed(contentPath, allowedRoots)) {
2740 | return formatMCPResponse({
2741 | success: false,
2742 | error: {
2743 | code: "PERMISSION_DENIED",
2744 | message: getPermissionDeniedMessage(contentPath, allowedRoots),
2745 | resolution:
2746 | "Request access to this directory by starting the server with --root argument.",
2747 | },
2748 | metadata: {
2749 | toolVersion: packageJson.version,
2750 | executionTime: 0,
2751 | timestamp: new Date().toISOString(),
2752 | },
2753 | });
2754 | }
2755 |
2756 | const result = await handleValidateDiataxisContent(args, extra);
2757 |
2758 | // Return structured validation results as JSON
2759 | const validationSummary = {
2760 | status: result.success ? "PASSED" : "ISSUES FOUND",
2761 | confidence: `${result.confidence.overall}%`,
2762 | issuesFound: result.issues.length,
2763 | breakdown: {
2764 | errors: result.issues.filter((i) => i.type === "error").length,
2765 | warnings: result.issues.filter((i) => i.type === "warning").length,
2766 | info: result.issues.filter((i) => i.type === "info").length,
2767 | },
2768 | topIssues: result.issues.slice(0, 5).map((issue) => ({
2769 | type: issue.type.toUpperCase(),
2770 | category: issue.category,
2771 | file: issue.location.file,
2772 | description: issue.description,
2773 | })),
2774 | recommendations: result.recommendations,
2775 | nextSteps: result.nextSteps,
2776 | confidenceBreakdown: result.confidence.breakdown,
2777 | };
2778 |
2779 | return {
2780 | content: [
2781 | {
2782 | type: "text",
2783 | text: `Content validation ${
2784 | result.success ? "passed" : "found issues"
2785 | }. Overall confidence: ${result.confidence.overall}%.`,
2786 | },
2787 | {
2788 | type: "text",
2789 | text: `Issues found: ${result.issues.length} (${
2790 | result.issues.filter((i) => i.type === "error").length
2791 | } errors, ${
2792 | result.issues.filter((i) => i.type === "warning").length
2793 | } warnings)`,
2794 | },
2795 | {
2796 | type: "text",
2797 | text: JSON.stringify(validationSummary, null, 2),
2798 | },
2799 | ],
2800 | };
2801 | }
2802 |
2803 | case "validate_content": {
2804 | const result = await validateGeneralContent(args);
2805 |
2806 | // Return structured validation results as JSON
2807 | const contentSummary = {
2808 | status: result.success ? "PASSED" : "ISSUES FOUND",
2809 | summary: result.summary,
2810 | linksChecked: result.linksChecked || 0,
2811 | codeBlocksValidated: result.codeBlocksValidated || 0,
2812 | brokenLinks: result.brokenLinks || [],
2813 | codeErrors: (result.codeErrors || []).slice(0, 10), // Limit to first 10 errors
2814 | recommendations: result.recommendations || [],
2815 | };
2816 |
2817 | return {
2818 | content: [
2819 | {
2820 | type: "text",
2821 | text: `Content validation completed. Status: ${
2822 | result.success ? "PASSED" : "ISSUES FOUND"
2823 | }`,
2824 | },
2825 | {
2826 | type: "text",
2827 | text: `Results: ${result.linksChecked || 0} links checked, ${
2828 | result.codeBlocksValidated || 0
2829 | } code blocks validated`,
2830 | },
2831 | {
2832 | type: "text",
2833 | text: JSON.stringify(contentSummary, null, 2),
2834 | },
2835 | ],
2836 | };
2837 | }
2838 |
2839 | case "detect_documentation_gaps": {
2840 | const result = await detectDocumentationGaps(args);
2841 | return wrapToolResult(result, "detect_documentation_gaps");
2842 | }
2843 |
2844 | case "test_local_deployment": {
2845 | const result = await testLocalDeployment(args);
2846 | return wrapToolResult(result, "test_local_deployment");
2847 | }
2848 |
2849 | case "evaluate_readme_health": {
2850 | const result = await evaluateReadmeHealth(args as any);
2851 | return wrapToolResult(result, "evaluate_readme_health");
2852 | }
2853 |
2854 | case "readme_best_practices": {
2855 | const result = await readmeBestPractices(args as any);
2856 | return formatMCPResponse(result);
2857 | }
2858 |
2859 | case "check_documentation_links": {
2860 | // Check if documentation_path is allowed
2861 | const docLinksPath = (args as any)?.documentation_path;
2862 | if (docLinksPath && !isPathAllowed(docLinksPath, allowedRoots)) {
2863 | return formatMCPResponse({
2864 | success: false,
2865 | error: {
2866 | code: "PERMISSION_DENIED",
2867 | message: getPermissionDeniedMessage(docLinksPath, allowedRoots),
2868 | resolution:
2869 | "Request access to this directory by starting the server with --root argument.",
2870 | },
2871 | metadata: {
2872 | toolVersion: packageJson.version,
2873 | executionTime: 0,
2874 | timestamp: new Date().toISOString(),
2875 | },
2876 | });
2877 | }
2878 |
2879 | const result = await checkDocumentationLinks(args as any);
2880 | return formatMCPResponse(result);
2881 | }
2882 |
2883 | case "generate_readme_template": {
2884 | const result = await generateReadmeTemplate(args as any);
2885 | return formatMCPResponse({
2886 | success: true,
2887 | data: result,
2888 | metadata: {
2889 | toolVersion: packageJson.version,
2890 | executionTime: Date.now(),
2891 | timestamp: new Date().toISOString(),
2892 | },
2893 | });
2894 | }
2895 |
2896 | case "validate_readme_checklist": {
2897 | const result = await validateReadmeChecklist(args as any);
2898 | return formatMCPResponse({
2899 | success: true,
2900 | data: result,
2901 | metadata: {
2902 | toolVersion: packageJson.version,
2903 | executionTime: Date.now(),
2904 | timestamp: new Date().toISOString(),
2905 | },
2906 | });
2907 | }
2908 |
2909 | case "analyze_readme": {
2910 | const result = await analyzeReadme(args as any);
2911 | return formatMCPResponse(result);
2912 | }
2913 |
2914 | case "manage_preferences": {
2915 | const result = await managePreferences(args);
2916 | return wrapToolResult(result, "manage_preferences");
2917 | }
2918 |
2919 | case "analyze_deployments": {
2920 | const result = await analyzeDeployments(args);
2921 | return wrapToolResult(result, "analyze_deployments");
2922 | }
2923 |
2924 | // Phase 3: Code-to-Documentation Synchronization
2925 | case "sync_code_to_docs": {
2926 | const projectPath = (args as any)?.projectPath;
2927 | const docsPath = (args as any)?.docsPath;
2928 |
2929 | // Check if paths are allowed
2930 | if (projectPath && !isPathAllowed(projectPath, allowedRoots)) {
2931 | return formatMCPResponse({
2932 | success: false,
2933 | error: {
2934 | code: "PERMISSION_DENIED",
2935 | message: getPermissionDeniedMessage(projectPath, allowedRoots),
2936 | resolution:
2937 | "Request access to this directory by starting the server with --root argument",
2938 | },
2939 | metadata: {
2940 | toolVersion: packageJson.version,
2941 | executionTime: 0,
2942 | timestamp: new Date().toISOString(),
2943 | },
2944 | });
2945 | }
2946 |
2947 | if (docsPath && !isPathAllowed(docsPath, allowedRoots)) {
2948 | return formatMCPResponse({
2949 | success: false,
2950 | error: {
2951 | code: "PERMISSION_DENIED",
2952 | message: getPermissionDeniedMessage(docsPath, allowedRoots),
2953 | resolution:
2954 | "Request access to this directory by starting the server with --root argument",
2955 | },
2956 | metadata: {
2957 | toolVersion: packageJson.version,
2958 | executionTime: 0,
2959 | timestamp: new Date().toISOString(),
2960 | },
2961 | });
2962 | }
2963 |
2964 | const result = await handleSyncCodeToDocs(args, extra);
2965 | return wrapToolResult(result, "sync_code_to_docs");
2966 | }
2967 |
2968 | case "change_watcher": {
2969 | const projectPath = (args as any)?.projectPath;
2970 | const docsPath = (args as any)?.docsPath;
2971 | const watchPaths = (args as any)?.watchPaths as string[] | undefined;
2972 |
2973 | const checkPath = (p?: string) => {
2974 | if (p && !isPathAllowed(p, allowedRoots)) {
2975 | return getPermissionDeniedMessage(p, allowedRoots);
2976 | }
2977 | return null;
2978 | };
2979 |
2980 | const projectError = checkPath(projectPath);
2981 | if (projectError) {
2982 | return formatMCPResponse({
2983 | success: false,
2984 | error: {
2985 | code: "PERMISSION_DENIED",
2986 | message: projectError,
2987 | resolution:
2988 | "Request access to this directory by starting the server with --root argument.",
2989 | },
2990 | metadata: {
2991 | toolVersion: packageJson.version,
2992 | executionTime: 0,
2993 | timestamp: new Date().toISOString(),
2994 | },
2995 | });
2996 | }
2997 |
2998 | const docsError = checkPath(docsPath);
2999 | if (docsError) {
3000 | return formatMCPResponse({
3001 | success: false,
3002 | error: {
3003 | code: "PERMISSION_DENIED",
3004 | message: docsError,
3005 | resolution:
3006 | "Request access to this directory by starting the server with --root argument.",
3007 | },
3008 | metadata: {
3009 | toolVersion: packageJson.version,
3010 | executionTime: 0,
3011 | timestamp: new Date().toISOString(),
3012 | },
3013 | });
3014 | }
3015 |
3016 | if (watchPaths && watchPaths.length > 0) {
3017 | for (const wp of watchPaths) {
3018 | const candidate =
3019 | projectPath && !path.isAbsolute(wp)
3020 | ? path.join(projectPath, wp)
3021 | : wp;
3022 | if (!isPathAllowed(candidate, allowedRoots)) {
3023 | return formatMCPResponse({
3024 | success: false,
3025 | error: {
3026 | code: "PERMISSION_DENIED",
3027 | message: getPermissionDeniedMessage(candidate, allowedRoots),
3028 | resolution:
3029 | "Request access to these paths by starting the server with --root argument.",
3030 | },
3031 | metadata: {
3032 | toolVersion: packageJson.version,
3033 | executionTime: 0,
3034 | timestamp: new Date().toISOString(),
3035 | },
3036 | });
3037 | }
3038 | }
3039 | }
3040 |
3041 | const result = await handleChangeWatcher(args, extra);
3042 | return wrapToolResult(result, "change_watcher");
3043 | }
3044 |
3045 | case "generate_contextual_content": {
3046 | const filePath = (args as any)?.filePath;
3047 |
3048 | // Check if file path is allowed
3049 | if (filePath && !isPathAllowed(filePath, allowedRoots)) {
3050 | return formatMCPResponse({
3051 | success: false,
3052 | error: {
3053 | code: "PERMISSION_DENIED",
3054 | message: getPermissionDeniedMessage(filePath, allowedRoots),
3055 | resolution:
3056 | "Request access to this file by starting the server with --root argument",
3057 | },
3058 | metadata: {
3059 | toolVersion: packageJson.version,
3060 | executionTime: 0,
3061 | timestamp: new Date().toISOString(),
3062 | },
3063 | });
3064 | }
3065 |
3066 | const result = await handleGenerateContextualContent(args, extra);
3067 | return wrapToolResult(result, "generate_contextual_content");
3068 | }
3069 |
3070 | // Execution Simulation (Issue #73)
3071 | case "simulate_execution": {
3072 | const implementationPath = (args as any)?.implementationPath;
3073 |
3074 | // Check if implementation path is allowed (if provided)
3075 | if (
3076 | implementationPath &&
3077 | !isPathAllowed(implementationPath, allowedRoots)
3078 | ) {
3079 | return formatMCPResponse({
3080 | success: false,
3081 | error: {
3082 | code: "PERMISSION_DENIED",
3083 | message: getPermissionDeniedMessage(
3084 | implementationPath,
3085 | allowedRoots,
3086 | ),
3087 | resolution:
3088 | "Request access to this file by starting the server with --root argument",
3089 | },
3090 | metadata: {
3091 | toolVersion: packageJson.version,
3092 | executionTime: 0,
3093 | timestamp: new Date().toISOString(),
3094 | },
3095 | });
3096 | }
3097 |
3098 | const simResult = await handleSimulateExecution(args as any, extra);
3099 | return wrapToolResult(simResult, "simulate_execution");
3100 | }
3101 |
3102 | case "batch_simulate_execution": {
3103 | // Check all implementation paths if provided
3104 | const batchExamples = (args as any)?.examples || [];
3105 | for (const example of batchExamples) {
3106 | if (
3107 | example.implementationPath &&
3108 | !isPathAllowed(example.implementationPath, allowedRoots)
3109 | ) {
3110 | return formatMCPResponse({
3111 | success: false,
3112 | error: {
3113 | code: "PERMISSION_DENIED",
3114 | message: getPermissionDeniedMessage(
3115 | example.implementationPath,
3116 | allowedRoots,
3117 | ),
3118 | resolution:
3119 | "Request access to this file by starting the server with --root argument",
3120 | },
3121 | metadata: {
3122 | toolVersion: packageJson.version,
3123 | executionTime: 0,
3124 | timestamp: new Date().toISOString(),
3125 | },
3126 | });
3127 | }
3128 | }
3129 |
3130 | const batchResult = await handleBatchSimulateExecution(
3131 | args as any,
3132 | extra,
3133 | );
3134 | return wrapToolResult(batchResult, "batch_simulate_execution");
3135 | }
3136 |
3137 | // Documentation Freshness Tracking
3138 | case "track_documentation_freshness": {
3139 | const docsPath = (args as any)?.docsPath;
3140 |
3141 | // Check if docs path is allowed
3142 | if (docsPath && !isPathAllowed(docsPath, allowedRoots)) {
3143 | return formatMCPResponse({
3144 | success: false,
3145 | error: {
3146 | code: "PERMISSION_DENIED",
3147 | message: getPermissionDeniedMessage(docsPath, allowedRoots),
3148 | resolution:
3149 | "Request access to this directory by starting the server with --root argument",
3150 | },
3151 | metadata: {
3152 | toolVersion: packageJson.version,
3153 | executionTime: 0,
3154 | timestamp: new Date().toISOString(),
3155 | },
3156 | });
3157 | }
3158 |
3159 | const result = await trackDocumentationFreshness(args as any);
3160 | return wrapToolResult(result, "track_documentation_freshness");
3161 | }
3162 |
3163 | case "validate_documentation_freshness": {
3164 | const docsPath = (args as any)?.docsPath;
3165 | const projectPath = (args as any)?.projectPath;
3166 |
3167 | // Check if paths are allowed
3168 | if (docsPath && !isPathAllowed(docsPath, allowedRoots)) {
3169 | return formatMCPResponse({
3170 | success: false,
3171 | error: {
3172 | code: "PERMISSION_DENIED",
3173 | message: getPermissionDeniedMessage(docsPath, allowedRoots),
3174 | resolution:
3175 | "Request access to this directory by starting the server with --root argument",
3176 | },
3177 | metadata: {
3178 | toolVersion: packageJson.version,
3179 | executionTime: 0,
3180 | timestamp: new Date().toISOString(),
3181 | },
3182 | });
3183 | }
3184 |
3185 | if (projectPath && !isPathAllowed(projectPath, allowedRoots)) {
3186 | return formatMCPResponse({
3187 | success: false,
3188 | error: {
3189 | code: "PERMISSION_DENIED",
3190 | message: getPermissionDeniedMessage(projectPath, allowedRoots),
3191 | resolution:
3192 | "Request access to this directory by starting the server with --root argument",
3193 | },
3194 | metadata: {
3195 | toolVersion: packageJson.version,
3196 | executionTime: 0,
3197 | timestamp: new Date().toISOString(),
3198 | },
3199 | });
3200 | }
3201 |
3202 | const result = await validateDocumentationFreshness(args as any);
3203 | return wrapToolResult(result, "validate_documentation_freshness");
3204 | }
3205 |
3206 | case "manage_sitemap": {
3207 | const docsPath = (args as any)?.docsPath;
3208 |
3209 | // Check if docs path is allowed
3210 | if (docsPath && !isPathAllowed(docsPath, allowedRoots)) {
3211 | return formatMCPResponse({
3212 | success: false,
3213 | error: {
3214 | code: "PERMISSION_DENIED",
3215 | message: getPermissionDeniedMessage(docsPath, allowedRoots),
3216 | resolution:
3217 | "Request access to this directory by starting the server with --root argument",
3218 | },
3219 | metadata: {
3220 | toolVersion: packageJson.version,
3221 | executionTime: 0,
3222 | timestamp: new Date().toISOString(),
3223 | },
3224 | });
3225 | }
3226 |
3227 | const result = await manageSitemap(args as any);
3228 | return wrapToolResult(result, "manage_sitemap");
3229 | }
3230 |
3231 | case "generate_llm_context": {
3232 | const projectPath = (args as any)?.projectPath;
3233 |
3234 | // Check if project path is allowed
3235 | if (projectPath && !isPathAllowed(projectPath, allowedRoots)) {
3236 | return formatMCPResponse({
3237 | success: false,
3238 | error: {
3239 | code: "PERMISSION_DENIED",
3240 | message: getPermissionDeniedMessage(projectPath, allowedRoots),
3241 | resolution:
3242 | "Request access to this directory by starting the server with --root argument",
3243 | },
3244 | metadata: {
3245 | toolVersion: packageJson.version,
3246 | executionTime: 0,
3247 | timestamp: new Date().toISOString(),
3248 | },
3249 | });
3250 | }
3251 |
3252 | const result = await generateLLMContext(args as any);
3253 | return wrapToolResult(result, "generate_llm_context");
3254 | }
3255 |
3256 | case "cleanup_agent_artifacts": {
3257 | const artifactPath = (args as any)?.path;
3258 |
3259 | // Check if path is allowed
3260 | if (artifactPath && !isPathAllowed(artifactPath, allowedRoots)) {
3261 | return formatMCPResponse({
3262 | success: false,
3263 | error: {
3264 | code: "PERMISSION_DENIED",
3265 | message: getPermissionDeniedMessage(artifactPath, allowedRoots),
3266 | resolution:
3267 | "Request access to this directory by starting the server with --root argument",
3268 | },
3269 | metadata: {
3270 | toolVersion: packageJson.version,
3271 | executionTime: 0,
3272 | timestamp: new Date().toISOString(),
3273 | },
3274 | });
3275 | }
3276 |
3277 | const result = await cleanupAgentArtifacts(args);
3278 | return wrapToolResult(result, "cleanup_agent_artifacts");
3279 | }
3280 |
3281 | case "read_directory": {
3282 | const { path: dirPath } = args as { path: string };
3283 |
3284 | // Check if path is allowed
3285 | if (!isPathAllowed(dirPath, allowedRoots)) {
3286 | return formatMCPResponse({
3287 | success: false,
3288 | error: {
3289 | code: "PERMISSION_DENIED",
3290 | message: getPermissionDeniedMessage(dirPath, allowedRoots),
3291 | resolution:
3292 | "Request access to this directory by starting the server with --root argument, or use a path within allowed roots.",
3293 | },
3294 | metadata: {
3295 | toolVersion: packageJson.version,
3296 | executionTime: 0,
3297 | timestamp: new Date().toISOString(),
3298 | },
3299 | });
3300 | }
3301 |
3302 | try {
3303 | const entries = await fs.readdir(dirPath, { withFileTypes: true });
3304 | const files = [];
3305 | const directories = [];
3306 |
3307 | for (const entry of entries) {
3308 | if (entry.isDirectory()) {
3309 | directories.push(entry.name);
3310 | } else if (entry.isFile()) {
3311 | files.push(entry.name);
3312 | }
3313 | }
3314 |
3315 | return formatMCPResponse({
3316 | success: true,
3317 | data: {
3318 | path: dirPath,
3319 | files,
3320 | directories,
3321 | totalFiles: files.length,
3322 | totalDirectories: directories.length,
3323 | },
3324 | metadata: {
3325 | toolVersion: packageJson.version,
3326 | executionTime: 0,
3327 | timestamp: new Date().toISOString(),
3328 | },
3329 | });
3330 | } catch (error: any) {
3331 | return formatMCPResponse({
3332 | success: false,
3333 | error: {
3334 | code: "READ_DIRECTORY_FAILED",
3335 | message: `Failed to read directory: ${error.message}`,
3336 | resolution: "Ensure the directory exists and is accessible.",
3337 | },
3338 | metadata: {
3339 | toolVersion: packageJson.version,
3340 | executionTime: 0,
3341 | timestamp: new Date().toISOString(),
3342 | },
3343 | });
3344 | }
3345 | }
3346 |
3347 | case "optimize_readme": {
3348 | const result = await optimizeReadme(args as any);
3349 | return formatMCPResponse(result);
3350 | }
3351 |
3352 | // Memory system tools
3353 | case "memory_recall": {
3354 | await initializeMemory(); // Ensure memory is initialized
3355 | const manager = (await import("./memory/index.js")).getMemoryManager();
3356 | if (!manager) throw new Error("Memory system not initialized");
3357 |
3358 | let results;
3359 | if (args?.type === "all") {
3360 | results = await manager.search(args?.query || "", {
3361 | sortBy: "timestamp",
3362 | });
3363 | } else {
3364 | results = await manager.search(args?.type || "analysis", {
3365 | sortBy: "timestamp",
3366 | });
3367 | }
3368 |
3369 | if (args?.limit && typeof args.limit === "number") {
3370 | results = results.slice(0, args.limit);
3371 | }
3372 |
3373 | return {
3374 | content: [
3375 | {
3376 | type: "text",
3377 | text: `Found ${results.length} memories`,
3378 | },
3379 | {
3380 | type: "text",
3381 | text: JSON.stringify(results, null, 2),
3382 | },
3383 | ],
3384 | };
3385 | }
3386 |
3387 | case "memory_insights": {
3388 | const insights = await getMemoryStatistics();
3389 | if (args?.projectId && typeof args.projectId === "string") {
3390 | const projectInsights = await getProjectInsights(args.projectId);
3391 | (insights as any).projectSpecific = projectInsights;
3392 | }
3393 |
3394 | return {
3395 | content: [
3396 | {
3397 | type: "text",
3398 | text: "Memory system insights and patterns",
3399 | },
3400 | {
3401 | type: "text",
3402 | text: JSON.stringify(insights, null, 2),
3403 | },
3404 | ],
3405 | };
3406 | }
3407 |
3408 | case "memory_similar": {
3409 | await initializeMemory();
3410 | const manager = (await import("./memory/index.js")).getMemoryManager();
3411 | if (!manager) throw new Error("Memory system not initialized");
3412 |
3413 | if (!args?.analysisId || typeof args.analysisId !== "string") {
3414 | throw new Error("analysisId is required");
3415 | }
3416 |
3417 | const analysis = await manager.recall(args.analysisId);
3418 | if (!analysis) {
3419 | throw new Error(`Analysis ${args.analysisId} not found in memory`);
3420 | }
3421 |
3422 | const limitValue = typeof args?.limit === "number" ? args.limit : 5;
3423 | const similar = await getSimilarProjects(analysis.data, limitValue);
3424 |
3425 | return {
3426 | content: [
3427 | {
3428 | type: "text",
3429 | text: `Found ${similar.length} similar projects`,
3430 | },
3431 | {
3432 | type: "text",
3433 | text: JSON.stringify(similar, null, 2),
3434 | },
3435 | ],
3436 | };
3437 | }
3438 |
3439 | case "memory_export": {
3440 | const format =
3441 | args?.format === "json" || args?.format === "csv"
3442 | ? args.format
3443 | : "json";
3444 | const exported = await exportMemories(format);
3445 |
3446 | return {
3447 | content: [
3448 | {
3449 | type: "text",
3450 | text: `Exported memories in ${format} format`,
3451 | },
3452 | {
3453 | type: "text",
3454 | text: exported,
3455 | },
3456 | ],
3457 | };
3458 | }
3459 |
3460 | case "memory_cleanup": {
3461 | const daysToKeep =
3462 | typeof args?.daysToKeep === "number" ? args.daysToKeep : 30;
3463 |
3464 | if (args?.dryRun) {
3465 | const stats = await getMemoryStatistics();
3466 | const cutoff = new Date(
3467 | Date.now() - daysToKeep * 24 * 60 * 60 * 1000,
3468 | );
3469 | const oldCount = Object.entries(
3470 | (stats as any).statistics?.byMonth || {},
3471 | )
3472 | .filter(([month]) => new Date(month + "-01") < cutoff)
3473 | .reduce((sum, [_, count]) => sum + (count as number), 0);
3474 |
3475 | return {
3476 | content: [
3477 | {
3478 | type: "text",
3479 | text: `Dry run: Would delete approximately ${oldCount} memories older than ${daysToKeep} days`,
3480 | },
3481 | ],
3482 | };
3483 | } else {
3484 | const deleted = await cleanupOldMemories(daysToKeep);
3485 | return {
3486 | content: [
3487 | {
3488 | type: "text",
3489 | text: `Cleaned up ${deleted} old memories`,
3490 | },
3491 | ],
3492 | };
3493 | }
3494 | }
3495 |
3496 | case "memory_intelligent_analysis": {
3497 | const projectPath = args?.projectPath as string;
3498 | const baseAnalysis = args?.baseAnalysis as any;
3499 |
3500 | // Get insights and similar projects
3501 | const insights = await getProjectInsights(projectPath);
3502 | const similar = await getSimilarProjects(baseAnalysis, 5);
3503 |
3504 | // Build intelligent analysis
3505 | const intelligentAnalysis = {
3506 | projectPath,
3507 | contextualInsights: {
3508 | insights: insights,
3509 | similarProjects: similar.map((p: any) => ({
3510 | name: p.projectPath,
3511 | similarity: p.similarity,
3512 | technologies: p.technologies,
3513 | hasTests: p.hasTests,
3514 | hasDocs: p.hasDocs,
3515 | })),
3516 | documentationHealth: {
3517 | hasDocumentation: baseAnalysis?.documentation?.hasDocs || false,
3518 | coverage: baseAnalysis?.documentation?.coverage || "unknown",
3519 | recommendedImprovement: baseAnalysis?.documentation?.hasDocs
3520 | ? "Add missing documentation categories"
3521 | : "Create initial documentation structure",
3522 | },
3523 | },
3524 | patterns: {
3525 | technologyStack:
3526 | baseAnalysis?.technologies?.primaryLanguage || "unknown",
3527 | projectSize: baseAnalysis?.structure?.size || "unknown",
3528 | testingMaturity: baseAnalysis?.structure?.hasTests
3529 | ? "has tests"
3530 | : "no tests",
3531 | cicdMaturity: baseAnalysis?.structure?.hasCI
3532 | ? "has CI/CD"
3533 | : "no CI/CD",
3534 | },
3535 | predictions: {
3536 | recommendedSSG:
3537 | similar.length > 0
3538 | ? `Based on ${similar.length} similar projects`
3539 | : "Insufficient data",
3540 | estimatedEffort:
3541 | baseAnalysis?.structure?.size === "large"
3542 | ? "high"
3543 | : baseAnalysis?.structure?.size === "medium"
3544 | ? "medium"
3545 | : "low",
3546 | },
3547 | recommendations: [
3548 | ...(baseAnalysis?.documentation?.hasDocs
3549 | ? []
3550 | : ["Create documentation structure using Diataxis framework"]),
3551 | ...(baseAnalysis?.structure?.hasTests
3552 | ? []
3553 | : ["Add test coverage to improve reliability"]),
3554 | ...(baseAnalysis?.structure?.hasCI
3555 | ? []
3556 | : ["Set up CI/CD pipeline for automated deployment"]),
3557 | ],
3558 | };
3559 |
3560 | return {
3561 | content: [
3562 | {
3563 | type: "text",
3564 | text: JSON.stringify(intelligentAnalysis, null, 2),
3565 | },
3566 | ],
3567 | };
3568 | }
3569 |
3570 | case "memory_enhanced_recommendation": {
3571 | const projectPath = args?.projectPath as string;
3572 | const baseRecommendation = args?.baseRecommendation as any;
3573 | const projectFeatures = args?.projectFeatures as any;
3574 |
3575 | // Get historical deployment data and similar projects
3576 | await getProjectInsights(projectPath);
3577 | const similar = await getSimilarProjects(projectFeatures, 10);
3578 |
3579 | // Calculate success rates from similar projects
3580 | const successfulDeployments = similar.filter(
3581 | (p: any) => p.deploymentSuccess === true,
3582 | );
3583 | const ssgUsage: Record<string, number> = {};
3584 | similar.forEach((p: any) => {
3585 | if (p.recommendedSSG) {
3586 | ssgUsage[p.recommendedSSG] = (ssgUsage[p.recommendedSSG] || 0) + 1;
3587 | }
3588 | });
3589 |
3590 | const enhancedRecommendation = {
3591 | baseRecommendation: baseRecommendation?.ssg || "unknown",
3592 | confidence: baseRecommendation?.confidence || 0,
3593 | historicalContext: {
3594 | similarProjectsAnalyzed: similar.length,
3595 | successfulDeployments: successfulDeployments.length,
3596 | successRate:
3597 | similar.length > 0
3598 | ? (
3599 | (successfulDeployments.length / similar.length) *
3600 | 100
3601 | ).toFixed(1) + "%"
3602 | : "N/A",
3603 | },
3604 | popularChoices: Object.entries(ssgUsage)
3605 | .sort(([, a], [, b]) => (b as number) - (a as number))
3606 | .slice(0, 3)
3607 | .map(([ssg, count]) => ({
3608 | ssg,
3609 | usage: count,
3610 | percentage:
3611 | similar.length > 0
3612 | ? (((count as number) / similar.length) * 100).toFixed(1) +
3613 | "%"
3614 | : "N/A",
3615 | })),
3616 | enhancedRecommendations: [
3617 | {
3618 | ssg: baseRecommendation?.ssg || "Jekyll",
3619 | reason: "Base recommendation from analysis",
3620 | confidence: baseRecommendation?.confidence || 0.7,
3621 | },
3622 | ...Object.entries(ssgUsage)
3623 | .filter(([ssg]) => ssg !== baseRecommendation?.ssg)
3624 | .slice(0, 2)
3625 | .map(([ssg, count]) => ({
3626 | ssg,
3627 | reason: `Used by ${count} similar project(s)`,
3628 | confidence: similar.length > 0 ? count / similar.length : 0.5,
3629 | })),
3630 | ],
3631 | considerations: [
3632 | ...(projectFeatures.hasTests
3633 | ? ["Project has tests - consider SSG with good test integration"]
3634 | : []),
3635 | ...(projectFeatures.hasCI
3636 | ? ["Project has CI/CD - ensure SSG supports automated builds"]
3637 | : []),
3638 | ...(projectFeatures.complexity === "complex"
3639 | ? ["Complex project - consider robust SSG with plugin ecosystem"]
3640 | : []),
3641 | ...(projectFeatures.isOpenSource
3642 | ? ["Open source project - community support is important"]
3643 | : []),
3644 | ],
3645 | };
3646 |
3647 | return {
3648 | content: [
3649 | {
3650 | type: "text",
3651 | text: JSON.stringify(enhancedRecommendation, null, 2),
3652 | },
3653 | ],
3654 | };
3655 | }
3656 |
3657 | case "memory_learning_stats": {
3658 | const stats = await getMemoryStatistics();
3659 | return {
3660 | content: [
3661 | {
3662 | type: "text",
3663 | text: JSON.stringify(
3664 | {
3665 | status: "active",
3666 | learningStats: stats,
3667 | message: "Learning stats from current memory system",
3668 | },
3669 | null,
3670 | 2,
3671 | ),
3672 | },
3673 | ],
3674 | };
3675 | }
3676 |
3677 | case "memory_knowledge_graph": {
3678 | return {
3679 | content: [
3680 | {
3681 | type: "text",
3682 | text: JSON.stringify(
3683 | {
3684 | status: "development",
3685 | message: "Knowledge graph feature is being developed",
3686 | query: args?.query,
3687 | },
3688 | null,
3689 | 2,
3690 | ),
3691 | },
3692 | ],
3693 | };
3694 | }
3695 |
3696 | case "memory_contextual_search": {
3697 | return {
3698 | content: [
3699 | {
3700 | type: "text",
3701 | text: JSON.stringify(
3702 | {
3703 | status: "development",
3704 | message: "Contextual search feature is being developed",
3705 | query: args?.query,
3706 | context: args?.context,
3707 | },
3708 | null,
3709 | 2,
3710 | ),
3711 | },
3712 | ],
3713 | };
3714 | }
3715 |
3716 | case "memory_agent_network": {
3717 | return {
3718 | content: [
3719 | {
3720 | type: "text",
3721 | text: JSON.stringify(
3722 | {
3723 | status: "development",
3724 | message: "Agent network feature is being developed",
3725 | action: args?.action,
3726 | },
3727 | null,
3728 | 2,
3729 | ),
3730 | },
3731 | ],
3732 | };
3733 | }
3734 |
3735 | case "memory_pruning": {
3736 | return {
3737 | content: [
3738 | {
3739 | type: "text",
3740 | text: JSON.stringify(
3741 | {
3742 | status: "development",
3743 | message: "Memory pruning feature is being developed",
3744 | dryRun: args?.dryRun,
3745 | },
3746 | null,
3747 | 2,
3748 | ),
3749 | },
3750 | ],
3751 | };
3752 | }
3753 |
3754 | case "memory_temporal_analysis": {
3755 | return {
3756 | content: [
3757 | {
3758 | type: "text",
3759 | text: JSON.stringify(
3760 | {
3761 | status: "development",
3762 | message: "Temporal analysis feature is being developed",
3763 | query: args?.query,
3764 | },
3765 | null,
3766 | 2,
3767 | ),
3768 | },
3769 | ],
3770 | };
3771 | }
3772 |
3773 | case "memory_visualization": {
3774 | return {
3775 | content: [
3776 | {
3777 | type: "text",
3778 | text: JSON.stringify(
3779 | {
3780 | status: "development",
3781 | message: "Memory visualization feature is being developed",
3782 | visualizationType: args?.visualizationType,
3783 | },
3784 | null,
3785 | 2,
3786 | ),
3787 | },
3788 | ],
3789 | };
3790 | }
3791 |
3792 | case "memory_export_advanced": {
3793 | await initializeMemory();
3794 | const manager = (await import("./memory/index.js")).getMemoryManager();
3795 | if (!manager) throw new Error("Memory system not initialized");
3796 |
3797 | const result = await manager.export("json");
3798 | return {
3799 | content: [
3800 | {
3801 | type: "text",
3802 | text: JSON.stringify(
3803 | {
3804 | status: "success",
3805 | exported: result.length,
3806 | data: result,
3807 | },
3808 | null,
3809 | 2,
3810 | ),
3811 | },
3812 | ],
3813 | };
3814 | }
3815 |
3816 | case "memory_import_advanced": {
3817 | await initializeMemory();
3818 | const manager = (await import("./memory/index.js")).getMemoryManager();
3819 | if (!manager) throw new Error("Memory system not initialized");
3820 |
3821 | if (!args?.inputPath || typeof args.inputPath !== "string") {
3822 | throw new Error("inputPath is required");
3823 | }
3824 |
3825 | const fs = await import("fs/promises");
3826 | const data = await fs.readFile(args.inputPath, "utf-8");
3827 | const result = await manager.import(data, "json");
3828 | return {
3829 | content: [
3830 | {
3831 | type: "text",
3832 | text: JSON.stringify(
3833 | {
3834 | status: "success",
3835 | imported: result,
3836 | },
3837 | null,
3838 | 2,
3839 | ),
3840 | },
3841 | ],
3842 | };
3843 | }
3844 |
3845 | case "memory_migration": {
3846 | return {
3847 | content: [
3848 | {
3849 | type: "text",
3850 | text: JSON.stringify(
3851 | {
3852 | status: "development",
3853 | message: "Migration functionality not yet implemented",
3854 | action: args?.action,
3855 | },
3856 | null,
3857 | 2,
3858 | ),
3859 | },
3860 | ],
3861 | };
3862 | }
3863 |
3864 | case "memory_optimization_metrics": {
3865 | const stats = await getMemoryStatistics();
3866 | return {
3867 | content: [
3868 | {
3869 | type: "text",
3870 | text: JSON.stringify(
3871 | {
3872 | status: "active",
3873 | optimizationMetrics: stats,
3874 | message: "Optimization metrics from current memory system",
3875 | },
3876 | null,
3877 | 2,
3878 | ),
3879 | },
3880 | ],
3881 | };
3882 | }
3883 |
3884 | default:
3885 | throw new Error(`Unknown tool: ${name}`);
3886 | }
3887 | } catch (error) {
3888 | const errorMessage =
3889 | error instanceof Error ? error.message : "Unknown error occurred";
3890 |
3891 | return formatMCPResponse({
3892 | success: false,
3893 | error: {
3894 | code: "TOOL_EXECUTION_ERROR",
3895 | message: errorMessage,
3896 | details: error instanceof Error ? error.stack : undefined,
3897 | resolution:
3898 | "Check tool parameters and try again. If the issue persists, review server logs for details.",
3899 | },
3900 | metadata: {
3901 | toolVersion: packageJson.version,
3902 | executionTime: Date.now(),
3903 | timestamp: new Date().toISOString(),
3904 | },
3905 | });
3906 | }
3907 | });
3908 |
3909 | // Start the server
3910 | async function main() {
3911 | const transport = new StdioServerTransport();
3912 | await server.connect(transport);
3913 |
3914 | // Show storage information at startup
3915 | const storageDir =
3916 | process.env.DOCUMCP_STORAGE_DIR || `${process.cwd()}/.documcp/memory`;
3917 | console.error("DocuMCP server started successfully");
3918 | console.error(`Storage location: ${storageDir}`);
3919 | }
3920 |
3921 | main().catch((error) => {
3922 | console.error("Failed to start DocuMCP server:", error);
3923 | process.exit(1);
3924 | });
3925 |
```