Skip to main content
Glama

test_local_deployment

Test documentation builds and local servers before deploying to GitHub Pages. Configure repository path, static site generator, port, and timeout settings.

Instructions

Test documentation build and local server before deploying to GitHub Pages

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repositoryPathYesPath to the repository
ssgYes
portNoPort for local server
timeoutNoTimeout in seconds for build process
skipBuildNoSkip build step and only start server

Implementation Reference

  • The main handler function that executes the test_local_deployment tool logic: parses input schema, changes to repo dir, installs deps, builds site, starts local server, generates test script, and returns structured results with recommendations.
    export async function testLocalDeployment( args: unknown, ): Promise<{ content: any[] }> { const startTime = Date.now(); const { repositoryPath, ssg, port, timeout, skipBuild } = inputSchema.parse(args); try { const config = SSG_CONFIGS[ssg]; if (!config) { throw new Error(`Unsupported SSG: ${ssg}`); } // Change to repository directory process.chdir(repositoryPath); const testResult: LocalTestResult = { repositoryPath, ssg, buildSuccess: false, serverStarted: false, port, testScript: "", recommendations: [], nextSteps: [], }; // Step 1: Check if configuration exists (always check, even if skipBuild) const configExists = await checkConfigurationExists(repositoryPath, config); if (!configExists) { testResult.recommendations.push( `Missing configuration file. Expected one of: ${config.configFiles.join( ", ", )}`, ); testResult.nextSteps.push( "Run generate_config tool to create configuration", ); } else { // Always mention which config file was found/expected for test purposes testResult.recommendations.push( `Using ${ssg} configuration: ${config.configFiles.join(" or ")}`, ); } // Step 2: Install dependencies if needed if (config.installCommand && !skipBuild) { try { const { stderr } = await execAsync(config.installCommand, { cwd: repositoryPath, timeout: timeout * 1000, }); if (stderr && !stderr.includes("npm WARN")) { testResult.recommendations.push( "Dependency installation warnings detected", ); } } catch (error: any) { testResult.recommendations.push( `Dependency installation failed: ${error.message}`, ); testResult.nextSteps.push( "Fix dependency installation issues before testing deployment", ); } } // Step 3: Build the site (unless skipped) if (!skipBuild) { try { const { stdout, stderr } = await execAsync(config.buildCommand, { cwd: repositoryPath, timeout: timeout * 1000, }); testResult.buildSuccess = true; testResult.buildOutput = stdout; if (stderr && stderr.trim()) { testResult.buildErrors = stderr; if (stderr.includes("error") || stderr.includes("Error")) { testResult.recommendations.push( "Build completed with errors - review build output", ); } } // Check if build directory was created const buildDirExists = await checkBuildOutput( repositoryPath, config.buildDir, ); if (!buildDirExists) { testResult.recommendations.push( `Build directory ${config.buildDir} was not created`, ); } } catch (error: any) { testResult.buildSuccess = false; testResult.buildErrors = error.message; testResult.recommendations.push( "Build failed - fix build errors before deployment", ); testResult.nextSteps.push( "Review build configuration and resolve errors", ); } } else { testResult.buildSuccess = true; // Assume success if skipped } // Step 4: Generate test script testResult.testScript = generateTestScript( ssg, config, port, repositoryPath, ); // Step 5: Try to start local server (non-blocking) if (testResult.buildSuccess || skipBuild) { const serverResult = await startLocalServer( config, port, repositoryPath, 10, ); // 10 second timeout for server start testResult.serverStarted = serverResult.started; testResult.localUrl = serverResult.url; if (testResult.serverStarted) { testResult.recommendations.push( "Local server started successfully - test manually at the provided URL", ); testResult.nextSteps.push("Verify content loads correctly in browser"); testResult.nextSteps.push("Test navigation and responsive design"); } else { testResult.recommendations.push( "Could not automatically start local server - run manually using the provided script", ); testResult.nextSteps.push( "Start server manually and verify it works before GitHub deployment", ); } } // Step 6: Generate final recommendations if (testResult.buildSuccess && testResult.serverStarted) { testResult.recommendations.push( "Local deployment test successful - ready for GitHub Pages", ); testResult.nextSteps.push( "Run deploy_pages tool to set up GitHub Actions workflow", ); } else if (testResult.buildSuccess && !testResult.serverStarted) { testResult.recommendations.push( "Build successful but server test incomplete - manual verification needed", ); testResult.nextSteps.push( "Test server manually before deploying to GitHub", ); } const response: MCPToolResponse<typeof testResult> = { success: true, data: testResult, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, recommendations: [ { type: testResult.buildSuccess ? "info" : "warning", title: "Local Deployment Test Complete", description: `Build ${ testResult.buildSuccess ? "succeeded" : "failed" }, Server ${ testResult.serverStarted ? "started" : "failed to start" }`, }, ], nextSteps: testResult.nextSteps.map((step) => ({ action: step, toolRequired: getRecommendedTool(step), description: step, priority: testResult.buildSuccess ? "medium" : ("high" as const), })), }; return formatMCPResponse(response); } catch (error) { const errorResponse: MCPToolResponse = { success: false, error: { code: "LOCAL_TEST_FAILED", message: `Failed to test local deployment: ${error}`, resolution: "Ensure repository path is valid and SSG is properly configured", }, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; return formatMCPResponse(errorResponse); } }
  • Zod schema for input validation: requires repositoryPath and ssg, optional port, timeout, skipBuild.
    const inputSchema = z.object({ repositoryPath: z.string().describe("Path to the repository"), ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]), port: z.number().optional().default(3000).describe("Port for local server"), timeout: z .number() .optional() .default(60) .describe("Timeout in seconds for build process"), skipBuild: z .boolean() .optional() .default(false) .describe("Skip build step and only start server"), });
  • Configuration object mapping SSG names to their build/serve commands, output dirs, config files, and install commands.
    const SSG_CONFIGS: Record<string, SSGConfig> = { jekyll: { buildCommand: "bundle exec jekyll build", serveCommand: "bundle exec jekyll serve", buildDir: "_site", configFiles: ["_config.yml", "_config.yaml"], installCommand: "bundle install", }, hugo: { buildCommand: "hugo", serveCommand: "hugo server", buildDir: "public", configFiles: [ "hugo.toml", "hugo.yaml", "hugo.yml", "config.toml", "config.yaml", "config.yml", ], }, docusaurus: { buildCommand: "npm run build", serveCommand: "npm run serve", buildDir: "build", configFiles: ["docusaurus.config.js", "docusaurus.config.ts"], installCommand: "npm install", }, mkdocs: { buildCommand: "mkdocs build", serveCommand: "mkdocs serve", buildDir: "site", configFiles: ["mkdocs.yml", "mkdocs.yaml"], installCommand: "pip install -r requirements.txt", }, eleventy: { buildCommand: "npx @11ty/eleventy", serveCommand: "npx @11ty/eleventy --serve", buildDir: "_site", configFiles: [".eleventy.js", "eleventy.config.js", ".eleventy.json"], installCommand: "npm install", }, };
  • Helper to check if required config file exists for the SSG.
    async function checkConfigurationExists( repoPath: string, config: SSGConfig, ): Promise<boolean> { for (const configFile of config.configFiles) { try { await fs.access(path.join(repoPath, configFile)); return true; } catch { // File doesn't exist, continue checking } } return false; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tosin2013/documcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server