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