Skip to main content
Glama

Netlify MCP Server

index.ts144 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListRootsRequestSchema, CreateMessageRequestSchema, LATEST_PROTOCOL_VERSION, ProgressTokenSchema, CursorSchema, } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; import { execSync } from "child_process"; import { EventEmitter } from "events"; import { createServer, IncomingMessage, ServerResponse } from "http"; import { WebSocketServer } from "ws"; import * as fs from "fs"; import * as path from "path"; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Import enhancement modules (enabled for full feature set) import { EnhancedSSETransport } from "./transport/sse-enhanced.js"; import { AdvancedAnalytics } from "./analytics/advanced-analytics.js"; import { CustomWorkflowManager } from "./workflows/custom-workflows.js"; import { PluginManager } from "./plugins/plugin-manager.js"; import { PerformanceOptimizer } from "./performance/performance-optimizer.js"; // Global event emitter for resource updates const resourceEmitter = new EventEmitter(); // Initialize enhancement systems with latest features const analytics = new AdvancedAnalytics(path.join(__dirname, "analytics")); const workflowManager = new CustomWorkflowManager(path.join(__dirname, "workflows")); const pluginManager = new PluginManager(path.join(__dirname, "plugins")); const performanceOptimizer = new PerformanceOptimizer({ caching: { enabled: true, ttl: 300000, // 5 minutes maxSize: 1000, strategy: "lru", }, concurrency: { maxConcurrentOperations: 20, queueMaxSize: 2000, workerPoolSize: 4, }, optimization: { enableRequestBatching: true, batchTimeout: 50, enableCompression: true, enableLazyLoading: true, }, }); // Enhanced SSE transport instance let enhancedSSETransport: EnhancedSSETransport | null = null; // HTTP server for SSE transport let httpServer: ReturnType<typeof createServer> | null = null; // Create server instance with latest MCP SDK features and protocol version const server = new Server({ name: "netlify-mcp-server", version: "2.0.0", protocolVersion: LATEST_PROTOCOL_VERSION, }, { capabilities: { tools: { listChanged: true, }, resources: { subscribe: true, listChanged: true, }, prompts: { listChanged: true, }, roots: { listChanged: true, }, logging: { // Enable logging capabilities }, experimental: { // Enable experimental features customWorkflows: true, advancedAnalytics: true, pluginSystem: true, performanceOptimization: true, enhancedSSE: true, }, }, }); // Helper function for executing Netlify CLI commands with enhanced logging, performance optimization, and analytics async function executeNetlifyCommand(command: string, siteId?: string): Promise<string> { // LAZY LOADING: Check for authentication token ONLY when commands are executed, not when tools are listed if (!process.env.NETLIFY_AUTH_TOKEN) { throw new Error( "NETLIFY_AUTH_TOKEN environment variable is required. " + "Please set your Netlify Personal Access Token. " + "Get one from: https://app.netlify.com/user/applications#personal-access-tokens" ); } const startTime = Date.now(); const cacheKey = `netlify_cmd_${command}_${siteId || 'global'}`; return performanceOptimizer.executeOptimized( async () => { try { console.error(`[${new Date().toISOString()}] Executing: netlify ${command}`); analytics.trackEvent("command", "netlify", "execute", command, undefined, { siteId }); const env = { ...process.env }; if (siteId) { env['NETLIFY_SITE_ID'] = siteId; console.error(`[${new Date().toISOString()}] Using NETLIFY_SITE_ID: ${siteId}`); } const output = execSync(`netlify ${command}`, { encoding: 'utf8', env: env }); const duration = Date.now() - startTime; console.error(`[${new Date().toISOString()}] Success: ${output.substring(0, 100)}...`); // Track successful execution analytics.trackPerformance(`netlify_${command}`, duration, true); // Emit resource update events for certain commands if (command.includes('deploy') || command.includes('env:set') || command.includes('sites:create')) { resourceEmitter.emit('resourceChanged', { command, siteId }); } // Execute hooks await pluginManager.executeHooks('command-executed', { command, siteId, success: true, duration }); return output; } catch (error) { const duration = Date.now() - startTime; console.error(`[${new Date().toISOString()}] Error executing command: netlify ${command}`, error); // Track failed execution analytics.trackPerformance(`netlify_${command}`, duration, false, error instanceof Error ? error.message : String(error)); analytics.trackError("command_execution", error instanceof Error ? error.message : String(error), command); // Execute error hooks await pluginManager.executeHooks('command-error', { command, siteId, error, duration }); if (error instanceof Error) { const stderr = (error as any).stderr ? (error as any).stderr.toString() : ''; throw new Error(`Netlify CLI error: ${error.message}\n${stderr}`); } throw error; } }, { cacheKey: command.includes('list') || command.includes('status') ? cacheKey : undefined, cacheTtl: 60000, // 1 minute cache for list/status commands priority: command.includes('deploy') ? 'high' : 'normal', } ); } // Enhanced site management with caching class SiteManager { private sitesCache: any[] = []; private lastCacheUpdate: number = 0; private cacheExpiry: number = 60000; // 1 minute async getSites(forceRefresh = false): Promise<any[]> { const now = Date.now(); if (!forceRefresh && this.sitesCache.length > 0 && (now - this.lastCacheUpdate) < this.cacheExpiry) { return this.sitesCache; } try { const output = await executeNetlifyCommand("sites:list --json"); this.sitesCache = JSON.parse(output); this.lastCacheUpdate = now; return this.sitesCache; } catch (error) { console.error("Failed to fetch sites:", error); return this.sitesCache; // Return cached data on error } } async getSiteById(siteId: string): Promise<any | null> { const sites = await this.getSites(); return sites.find(site => site.id === siteId || site.name === siteId) || null; } invalidateCache(): void { this.sitesCache = []; this.lastCacheUpdate = 0; } } const siteManager = new SiteManager(); // Resource subscription management const subscriptions = new Set<string>(); // Enhanced notification system resourceEmitter.on('resourceChanged', async (data) => { if (subscriptions.size > 0) { // Invalidate cache when resources change siteManager.invalidateCache(); // Send notifications to subscribers try { if (data.command.includes('deploy') && data.siteId) { await server.sendResourceUpdated({ uri: `netlify://sites/${data.siteId}/deploys` }); } if (data.command.includes('env:set') && data.siteId) { await server.sendResourceUpdated({ uri: `netlify://sites/${data.siteId}/env` }); } if (data.command.includes('sites:create')) { await server.sendResourceListChanged(); } } catch (error) { console.error("Failed to send resource update notification:", error); } } }); // Define Zod schemas for validation const DeploySiteSchema = z.object({ path: z.string().describe("Path to the site directory"), prod: z.boolean().optional().describe("Deploy to production"), message: z.string().optional().describe("Deploy message"), }); const ListSitesSchema = z.object({}); const SetEnvVarsSchema = z.object({ siteId: z.string().describe("Site ID or name"), envVars: z.record(z.string()).describe("Environment variables to set (key-value pairs)"), }); const DeployFunctionSchema = z.object({ functionName: z.string().describe("Function name to deploy"), functionPath: z.string().optional().describe("Path to function file"), runtime: z.string().optional().describe("Function runtime (nodejs, python, go)"), }); const InvokeFunctionSchema = z.object({ functionName: z.string().describe("Function name to invoke"), payload: z.string().optional().describe("JSON payload to send to function"), identity: z.record(z.string()).optional().describe("Identity object for testing"), querystring: z.record(z.string()).optional().describe("Query string parameters"), }); const ServeFunctionsSchema = z.object({ functionsDir: z.string().optional().describe("Functions directory path"), port: z.number().optional().describe("Port to serve functions on"), }); const BuildFunctionsSchema = z.object({ functionsDir: z.string().optional().describe("Functions source directory"), targetDir: z.string().optional().describe("Functions build target directory"), }); const CreateFunctionSchema = z.object({ name: z.string().describe("Function name"), template: z.string().optional().describe("Function template to use"), language: z.enum(["javascript", "typescript", "go", "rust"]).optional().describe("Programming language"), }); const GetLogsSchema = z.object({ siteId: z.string().describe("Site ID or name"), function: z.string().optional().describe("Optional: Specific function name to filter logs"), }); const TriggerBuildSchema = z.object({ siteId: z.string().describe("Site ID or name"), message: z.string().optional().describe("Optional: Deploy message"), }); const LinkSiteSchema = z.object({ siteId: z.string().optional().describe("Optional: Site ID to link to (otherwise interactive)"), }); const UnlinkSiteSchema = z.object({}); const GetStatusSchema = z.object({}); const ImportEnvSchema = z.object({ siteId: z.string().describe("Site ID or name"), filePath: z.string().describe("Path to the .env file to import"), replace: z.boolean().optional().describe("Replace existing variables instead of merging"), }); const BuildSiteSchema = z.object({ siteId: z.string().optional().describe("Optional: Site ID (if not linked)"), context: z.string().optional().describe("Optional: Build context (e.g., 'production', 'deploy-preview')"), dry: z.boolean().optional().describe("Optional: Run a dry build without executing commands"), }); const GetEnvVarSchema = z.object({ siteId: z.string().optional().describe("Optional: Site ID (if not linked)"), key: z.string().describe("The environment variable key to retrieve"), context: z.string().optional().describe("Optional: Specific context to get the value from"), scope: z.string().optional().describe("Optional: Specific scope (e.g., 'builds', 'functions')"), }); const UnsetEnvVarSchema = z.object({ siteId: z.string().optional().describe("Optional: Site ID (if not linked)"), key: z.string().describe("The environment variable key to unset"), context: z.string().optional().describe("Optional: Specific context to unset the value from (otherwise all)"), }); const CloneEnvVarsSchema = z.object({ fromSiteId: z.string().describe("Source Site ID"), toSiteId: z.string().describe("Destination Site ID"), }); const CreateSiteSchema = z.object({ name: z.string().optional().describe("Optional: Site name (subdomain)"), accountSlug: z.string().optional().describe("Optional: Account slug for the team"), }); const DeleteSiteSchema = z.object({ siteId: z.string().describe("Site ID to delete"), force: z.boolean().optional().default(true).describe("Force deletion without confirmation (default: true)"), }); // New schemas for additional Netlify features const GetSiteInfoSchema = z.object({ siteId: z.string().describe("Site ID to get information for"), }); const ListDeploysSchema = z.object({ siteId: z.string().describe("Site ID to list deploys for"), limit: z.number().optional().describe("Number of deploys to return (default: 10)"), }); const GetDeployInfoSchema = z.object({ deployId: z.string().describe("Deploy ID to get information for"), }); const CancelDeploySchema = z.object({ deployId: z.string().describe("Deploy ID to cancel"), }); const RestoreDeploySchema = z.object({ deployId: z.string().describe("Deploy ID to restore"), }); const ListFunctionsSchema = z.object({ siteId: z.string().describe("Site ID to list functions for"), }); const GetFormSubmissionsSchema = z.object({ siteId: z.string().describe("Site ID to get form submissions for"), formId: z.string().optional().describe("Optional: Specific form ID"), }); // Comprehensive missing Netlify CLI schemas for full feature coverage // Netlify Blobs Management const GetBlobSchema = z.object({ storeName: z.string().describe("Netlify Blobs store name"), key: z.string().describe("Blob key to retrieve"), outputFile: z.string().optional().describe("Optional: File path to save blob content"), }); const SetBlobSchema = z.object({ storeName: z.string().describe("Netlify Blobs store name"), key: z.string().describe("Blob key to set"), value: z.string().optional().describe("Optional: Blob value (if not reading from file)"), inputFile: z.string().optional().describe("Optional: File path to read blob content from"), }); const DeleteBlobSchema = z.object({ storeName: z.string().describe("Netlify Blobs store name"), key: z.string().describe("Blob key to delete"), }); const ListBlobsSchema = z.object({ storeName: z.string().describe("Netlify Blobs store name"), prefix: z.string().optional().describe("Optional: Key prefix to filter blobs"), }); // Dev Server Operations const StartDevServerSchema = z.object({ port: z.number().optional().describe("Port to run dev server on (default: 8888)"), host: z.string().optional().describe("Host to bind dev server to (default: localhost)"), dir: z.string().optional().describe("Directory to serve (default: current directory)"), command: z.string().optional().describe("Custom command to run"), targetPort: z.number().optional().describe("Port of local dev server to proxy"), framework: z.string().optional().describe("Framework to use for auto-detection"), live: z.boolean().optional().describe("Enable live reload"), }); const ServeBuiltSiteSchema = z.object({ dir: z.string().optional().describe("Directory to serve (default: publish directory)"), port: z.number().optional().describe("Port to serve on (default: 3999)"), host: z.string().optional().describe("Host to bind to (default: localhost)"), }); // Recipe Management const ListRecipesSchema = z.object({ category: z.string().optional().describe("Filter recipes by category"), }); const RunRecipeSchema = z.object({ recipeName: z.string().describe("Name of the recipe to run"), siteId: z.string().optional().describe("Site ID to run recipe on"), config: z.record(z.unknown()).optional().describe("Recipe configuration options"), }); // Advanced Function Management const BuildFunctionSchema = z.object({ functionName: z.string().describe("Function name to build"), src: z.string().optional().describe("Source directory for functions"), functionsDir: z.string().optional().describe("Functions directory"), }); const InvokeFunctionAdvancedSchema = z.object({ functionName: z.string().describe("Function name to invoke"), payload: z.string().optional().describe("JSON payload"), identity: z.record(z.string()).optional().describe("Identity object"), querystring: z.record(z.string()).optional().describe("Query parameters"), port: z.number().optional().describe("Port to invoke function on"), no_timeout: z.boolean().optional().describe("Disable function timeout"), }); // Advanced Site Management const InitSiteSchema = z.object({ name: z.string().optional().describe("Site name"), accountSlug: z.string().optional().describe("Account slug"), template: z.string().optional().describe("Template to use"), gitRemoteUrl: z.string().optional().describe("Git repository URL"), }); const OpenSiteSchema = z.object({ siteId: z.string().optional().describe("Site ID to open (default: current site)"), admin: z.boolean().optional().describe("Open admin dashboard instead of site"), }); // Advanced API Operations const CallNetlifyAPISchema = z.object({ endpoint: z.string().describe("API endpoint to call (e.g., 'listSites', 'getSite')"), data: z.record(z.unknown()).optional().describe("API call data"), method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).optional().describe("HTTP method"), raw: z.boolean().optional().describe("Return raw response"), }); const ListAPIMethodsSchema = z.object({ filter: z.string().optional().describe("Filter methods by name"), }); // Monitoring and Logs const StreamLogsSchema = z.object({ siteId: z.string().describe("Site ID to stream logs for"), functionName: z.string().optional().describe("Specific function to stream logs for"), level: z.enum(["trace", "debug", "info", "warn", "error"]).optional().describe("Log level filter"), duration: z.number().optional().describe("Stream duration in seconds"), }); // Account Management const SwitchAccountSchema = z.object({ accountSlug: z.string().describe("Account slug to switch to"), }); const WatchDeploySchema = z.object({ siteId: z.string().describe("Site ID to watch"), deployId: z.string().optional().describe("Specific deploy ID to watch"), timeout: z.number().optional().describe("Watch timeout in seconds"), }); // Form Management const ManageFormSchema = z.object({ siteId: z.string().describe("Site ID"), formId: z.string().describe("Form ID"), action: z.enum(["enable", "disable", "delete", "export"]).describe("Action to perform"), format: z.enum(["json", "csv"]).optional().describe("Export format"), }); // Analytics const GetAnalyticsSchema = z.object({ siteId: z.string().describe("Site ID to get analytics for"), from: z.string().optional().describe("Start date (YYYY-MM-DD)"), to: z.string().optional().describe("End date (YYYY-MM-DD)"), resolution: z.enum(["day", "hour"]).optional().describe("Data resolution"), }); const EnableBranchDeploySchema = z.object({ siteId: z.string().describe("Site ID"), branch: z.string().describe("Branch name to enable deploys for"), }); const DisableBranchDeploySchema = z.object({ siteId: z.string().describe("Site ID"), branch: z.string().describe("Branch name to disable deploys for"), }); // LAZY LOADING IMPLEMENTATION: Tools are listed without authentication checks // Authentication is only validated when tools are actually invoked in executeNetlifyCommand server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "deploy-site", description: "Deploy a site to Netlify with comprehensive validation and monitoring", inputSchema: zodToJsonSchema(DeploySiteSchema), annotations: { title: "Deploy Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "list-sites", description: "List all sites in your Netlify account", inputSchema: zodToJsonSchema(ListSitesSchema), annotations: { title: "List Sites", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "set-env-vars", description: "Set environment variables for a specific site", inputSchema: zodToJsonSchema(SetEnvVarsSchema), annotations: { title: "Set Environment Variables", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, { name: "delete-site", description: "Delete a site from Netlify (irreversible operation)", inputSchema: zodToJsonSchema(DeleteSiteSchema), annotations: { title: "Delete Site", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, { name: "get-logs", description: "Get function logs for a site", inputSchema: zodToJsonSchema(GetLogsSchema), annotations: { title: "Get Logs", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "trigger-build", description: "Trigger a new build and deploy", inputSchema: zodToJsonSchema(TriggerBuildSchema), annotations: { title: "Trigger Build", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "link-site", description: "Link current directory to a Netlify site", inputSchema: zodToJsonSchema(LinkSiteSchema), annotations: { title: "Link Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "unlink-site", description: "Unlink current directory from Netlify site", inputSchema: zodToJsonSchema(UnlinkSiteSchema), annotations: { title: "Unlink Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "get-status", description: "Get current Netlify status", inputSchema: zodToJsonSchema(GetStatusSchema), annotations: { title: "Get Status", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "import-env", description: "Import environment variables from file", inputSchema: zodToJsonSchema(ImportEnvSchema), annotations: { title: "Import Environment Variables", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, { name: "build-site", description: "Build site locally", inputSchema: zodToJsonSchema(BuildSiteSchema), annotations: { title: "Build Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "get-env-var", description: "Get a specific environment variable", inputSchema: zodToJsonSchema(GetEnvVarSchema), annotations: { title: "Get Environment Variable", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "unset-env-var", description: "Unset an environment variable", inputSchema: zodToJsonSchema(UnsetEnvVarSchema), annotations: { title: "Unset Environment Variable", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, { name: "clone-env-vars", description: "Clone environment variables between sites", inputSchema: zodToJsonSchema(CloneEnvVarsSchema), annotations: { title: "Clone Environment Variables", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, { name: "create-site", description: "Create a new Netlify site", inputSchema: zodToJsonSchema(CreateSiteSchema), annotations: { title: "Create Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "get-site-info", description: "Get detailed information about a site", inputSchema: zodToJsonSchema(GetSiteInfoSchema), annotations: { title: "Get Site Information", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "list-deploys", description: "List deploys for a site", inputSchema: zodToJsonSchema(ListDeploysSchema), annotations: { title: "List Deploys", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "get-deploy-info", description: "Get information about a specific deploy", inputSchema: zodToJsonSchema(GetDeployInfoSchema), annotations: { title: "Get Deploy Information", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "cancel-deploy", description: "Cancel a running deploy", inputSchema: zodToJsonSchema(CancelDeploySchema), annotations: { title: "Cancel Deploy", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, { name: "restore-deploy", description: "Restore a previous deploy", inputSchema: zodToJsonSchema(RestoreDeploySchema), annotations: { title: "Restore Deploy", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, { name: "list-functions", description: "List all functions for a site", inputSchema: zodToJsonSchema(ListFunctionsSchema), annotations: { title: "List Functions", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "get-form-submissions", description: "Get form submissions for a site", inputSchema: zodToJsonSchema(GetFormSubmissionsSchema), annotations: { title: "Get Form Submissions", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "enable-branch-deploy", description: "Enable branch deploys for a specific branch", inputSchema: zodToJsonSchema(EnableBranchDeploySchema), annotations: { title: "Enable Branch Deploy", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "disable-branch-deploy", description: "Disable branch deploys for a specific branch", inputSchema: zodToJsonSchema(DisableBranchDeploySchema), annotations: { title: "Disable Branch Deploy", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, // COMPREHENSIVE NETLIFY CLI FEATURES - Expanding from 23 to 45+ tools // Netlify Blobs Management { name: "get-blob", description: "Get a blob from Netlify Blobs storage", inputSchema: zodToJsonSchema(GetBlobSchema), annotations: { title: "Get Blob", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, { name: "set-blob", description: "Set a blob in Netlify Blobs storage", inputSchema: zodToJsonSchema(SetBlobSchema), annotations: { title: "Set Blob", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, { name: "delete-blob", description: "Delete a blob from Netlify Blobs storage", inputSchema: zodToJsonSchema(DeleteBlobSchema), annotations: { title: "Delete Blob", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false, }, }, { name: "list-blobs", description: "List blobs in Netlify Blobs storage", inputSchema: zodToJsonSchema(ListBlobsSchema), annotations: { title: "List Blobs", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, // Dev Server Operations { name: "start-dev-server", description: "Start Netlify dev server for local development", inputSchema: zodToJsonSchema(StartDevServerSchema), annotations: { title: "Start Dev Server", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "serve-built-site", description: "Serve a built site locally", inputSchema: zodToJsonSchema(ServeBuiltSiteSchema), annotations: { title: "Serve Built Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, // Recipe Management { name: "list-recipes", description: "List available Netlify recipes", inputSchema: zodToJsonSchema(ListRecipesSchema), annotations: { title: "List Recipes", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, { name: "run-recipe", description: "Run a Netlify recipe", inputSchema: zodToJsonSchema(RunRecipeSchema), annotations: { title: "Run Recipe", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, // Advanced Function Management { name: "build-function", description: "Build a Netlify function", inputSchema: zodToJsonSchema(BuildFunctionSchema), annotations: { title: "Build Function", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, { name: "invoke-function-advanced", description: "Invoke a Netlify function with advanced options", inputSchema: zodToJsonSchema(InvokeFunctionAdvancedSchema), annotations: { title: "Invoke Function Advanced", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, // Advanced Site Management { name: "init-site", description: "Initialize a new Netlify site with advanced options", inputSchema: zodToJsonSchema(InitSiteSchema), annotations: { title: "Initialize Site", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, }, { name: "open-site", description: "Open a Netlify site in browser", inputSchema: zodToJsonSchema(OpenSiteSchema), annotations: { title: "Open Site", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, // Advanced API Operations { name: "call-netlify-api", description: "Make a direct call to Netlify API", inputSchema: zodToJsonSchema(CallNetlifyAPISchema), annotations: { title: "Call Netlify API", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, { name: "list-api-methods", description: "List available Netlify API methods", inputSchema: zodToJsonSchema(ListAPIMethodsSchema), annotations: { title: "List API Methods", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, // Monitoring and Logs { name: "stream-logs", description: "Stream live logs from Netlify site or function", inputSchema: zodToJsonSchema(StreamLogsSchema), annotations: { title: "Stream Logs", readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, // Account Management { name: "switch-account", description: "Switch to a different Netlify account", inputSchema: zodToJsonSchema(SwitchAccountSchema), annotations: { title: "Switch Account", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, { name: "watch-deploy", description: "Watch a deploy in real-time", inputSchema: zodToJsonSchema(WatchDeploySchema), annotations: { title: "Watch Deploy", readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, // Form Management { name: "manage-form", description: "Manage Netlify forms (enable, disable, delete, export)", inputSchema: zodToJsonSchema(ManageFormSchema), annotations: { title: "Manage Form", readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false, }, }, // Analytics { name: "get-analytics", description: "Get site analytics data", inputSchema: zodToJsonSchema(GetAnalyticsSchema), annotations: { title: "Get Analytics", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, ], }; }); // Tool execution handler - authentication is validated here when tools are invoked server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "deploy-site": { const params = DeploySiteSchema.parse(args); let command = `deploy --dir="${params.path}"`; if (params.prod) command += " --prod"; if (params.message) command += ` --message="${params.message}"`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-sites": { const output = await executeNetlifyCommand("sites:list"); return { content: [{ type: "text", text: output }] }; } case "set-env-vars": { const params = SetEnvVarsSchema.parse(args); const results: string[] = []; for (const [key, value] of Object.entries(params.envVars)) { const command = `env:set ${key} "${value}"`; const output = await executeNetlifyCommand(command, params.siteId); results.push(`Set ${key}: ${output}`); } return { content: [{ type: "text", text: results.join("\n") }] }; } case "get-logs": { const params = GetLogsSchema.parse(args); let command = `logs:function`; if (params.function) command += ` ${params.function}`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "trigger-build": { const params = TriggerBuildSchema.parse(args); let command = `deploy --build`; if (params.message) command += ` --message "${params.message}"`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "link-site": { const params = LinkSiteSchema.parse(args); let command = `link`; if (params.siteId) command += ` --id ${params.siteId}`; else { throw new Error("Interactive linking not supported. Please provide a siteId."); } const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "unlink-site": { const command = `unlink`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "get-status": { const command = `status`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "import-env": { const params = ImportEnvSchema.parse(args); let command = `env:import ${params.filePath}`; if (params.replace) command += ` --replace`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "build-site": { const params = BuildSiteSchema.parse(args); let command = `build`; if (params.context) command += ` --context ${params.context}`; if (params.dry) command += ` --dry`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "get-env-var": { const params = GetEnvVarSchema.parse(args); let command = `env:get ${params.key}`; if (params.context) command += ` --context ${params.context}`; if (params.scope) command += ` --scope ${params.scope}`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "unset-env-var": { const params = UnsetEnvVarSchema.parse(args); let command = `env:unset ${params.key}`; if (params.context) command += ` --context ${params.context}`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "clone-env-vars": { const params = CloneEnvVarsSchema.parse(args); const command = `env:clone --to ${params.toSiteId} --from ${params.fromSiteId}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "create-site": { const params = CreateSiteSchema.parse(args); const accountSlug = params.accountSlug || "playhousehosting"; let command = `sites:create --account-slug ${accountSlug}`; if (params.name) command += ` --name "${params.name}"`; command += ` --disable-linking`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "delete-site": { const params = DeleteSiteSchema.parse(args); let command = `sites:delete ${params.siteId}`; if (params.force) command += ` --force`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "get-site-info": { const params = GetSiteInfoSchema.parse(args); const command = `api getSite --data='{"site_id":"${params.siteId}"}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-deploys": { const params = ListDeploysSchema.parse(args); let command = `api listSiteDeploys --data='{"site_id":"${params.siteId}"}'`; if (params.limit) { command = `api listSiteDeploys --data='{"site_id":"${params.siteId}","per_page":${params.limit}}'`; } const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "get-deploy-info": { const params = GetDeployInfoSchema.parse(args); const command = `api getDeploy --data='{"deploy_id":"${params.deployId}"}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "cancel-deploy": { const params = CancelDeploySchema.parse(args); const command = `api cancelSiteDeploy --data='{"deploy_id":"${params.deployId}"}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "restore-deploy": { const params = RestoreDeploySchema.parse(args); const command = `api restoreSiteDeploy --data='{"deploy_id":"${params.deployId}"}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-functions": { const params = ListFunctionsSchema.parse(args); const command = `functions:list --json`; const output = await executeNetlifyCommand(command, params.siteId); return { content: [{ type: "text", text: output }] }; } case "get-form-submissions": { const params = GetFormSubmissionsSchema.parse(args); let command = `api listFormSubmissions --data='{"site_id":"${params.siteId}"}'`; if (params.formId) { command = `api listFormSubmissions --data='{"form_id":"${params.formId}"}'`; } const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "enable-branch-deploy": { const params = EnableBranchDeploySchema.parse(args); const command = `api updateSite --data='{"site_id":"${params.siteId}","build_settings":{"allowed_branches":["${params.branch}"]}}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "disable-branch-deploy": { const params = DisableBranchDeploySchema.parse(args); const command = `api updateSite --data='{"site_id":"${params.siteId}","build_settings":{"allowed_branches":[]}}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "get-blob": { const params = GetBlobSchema.parse(args); let command = `blob:get ${params.storeName} ${params.key}`; if (params.outputFile) command += ` --output ${params.outputFile}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "set-blob": { const params = SetBlobSchema.parse(args); let command = `blob:set ${params.storeName} ${params.key}`; if (params.value) command += ` --value "${params.value}"`; if (params.inputFile) command += ` --input ${params.inputFile}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "delete-blob": { const params = DeleteBlobSchema.parse(args); const command = `blob:delete ${params.storeName} ${params.key}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-blobs": { const params = ListBlobsSchema.parse(args); let command = `blob:list ${params.storeName}`; if (params.prefix) command += ` --prefix ${params.prefix}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "start-dev-server": { const params = StartDevServerSchema.parse(args); let command = `dev`; if (params.port) command += ` --port ${params.port}`; if (params.host) command += ` --host ${params.host}`; if (params.dir) command += ` --dir ${params.dir}`; if (params.command) command += ` --command "${params.command}"`; if (params.targetPort) command += ` --target-port ${params.targetPort}`; if (params.framework) command += ` --framework ${params.framework}`; if (params.live) command += ` --live`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "serve-built-site": { const params = ServeBuiltSiteSchema.parse(args); let command = `serve`; if (params.dir) command += ` --dir ${params.dir}`; if (params.port) command += ` --port ${params.port}`; if (params.host) command += ` --host ${params.host}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-recipes": { const params = ListRecipesSchema.parse(args); let command = `recipes:list`; if (params.category) command += ` --category ${params.category}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "run-recipe": { const params = RunRecipeSchema.parse(args); let command = `recipes ${params.recipeName}`; if (params.siteId) command += ` --site-id ${params.siteId}`; if (params.config) command += ` --config '${JSON.stringify(params.config)}'`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "build-function": { const params = BuildFunctionSchema.parse(args); let command = `functions:build`; if (params.functionName) command += ` --name ${params.functionName}`; if (params.src) command += ` --src ${params.src}`; if (params.functionsDir) command += ` --functions ${params.functionsDir}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "invoke-function-advanced": { const params = InvokeFunctionAdvancedSchema.parse(args); let command = `functions:invoke ${params.functionName}`; if (params.payload) command += ` --payload '${params.payload}'`; if (params.identity) command += ` --identity '${JSON.stringify(params.identity)}'`; if (params.querystring) command += ` --querystring '${JSON.stringify(params.querystring)}'`; if (params.port) command += ` --port ${params.port}`; if (params.no_timeout) command += ` --no-timeout`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "init-site": { const params = InitSiteSchema.parse(args); let command = `sites:create`; if (params.name) command += ` --name "${params.name}"`; if (params.accountSlug) command += ` --account-slug ${params.accountSlug}`; if (params.template) command += ` --template "${params.template}"`; if (params.gitRemoteUrl) command += ` --git-remote-url "${params.gitRemoteUrl}"`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "open-site": { const params = OpenSiteSchema.parse(args); let command = `open`; if (params.siteId) command += ` --site ${params.siteId}`; if (params.admin) command += ` --admin`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "call-netlify-api": { const params = CallNetlifyAPISchema.parse(args); let command = `api ${params.endpoint}`; if (params.data) command += ` --data '${JSON.stringify(params.data)}'`; if (params.method) command += ` --method ${params.method}`; if (params.raw) command += ` --raw`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "list-api-methods": { const params = ListAPIMethodsSchema.parse(args); let command = `api --list`; if (params.filter) command += ` --filter ${params.filter}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "stream-logs": { const params = StreamLogsSchema.parse(args); let command = `logs ${params.siteId}`; if (params.functionName) command += ` --function ${params.functionName}`; if (params.level) command += ` --level ${params.level}`; if (params.duration) command += ` --duration ${params.duration}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "switch-account": { const params = SwitchAccountSchema.parse(args); const command = `switch ${params.accountSlug}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "watch-deploy": { const params = WatchDeploySchema.parse(args); let command = `watch ${params.siteId}`; if (params.deployId) command += ` --deploy ${params.deployId}`; if (params.timeout) command += ` --timeout ${params.timeout}`; const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "manage-form": { const params = ManageFormSchema.parse(args); let command = `api`; switch (params.action) { case "enable": command += ` updateForm --data='{"form_id":"${params.formId}","disabled":false}'`; break; case "disable": command += ` updateForm --data='{"form_id":"${params.formId}","disabled":true}'`; break; case "delete": command += ` deleteForm --data='{"form_id":"${params.formId}"}'`; break; case "export": command += ` listFormSubmissions --data='{"form_id":"${params.formId}"}'`; if (params.format === "csv") command += ` --format csv`; break; } const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } case "get-analytics": { const params = GetAnalyticsSchema.parse(args); let command = `api getAccountUsageByCapability --data='{"account_id":"current"}'`; // Note: Netlify CLI doesn't have direct analytics command, using API const output = await executeNetlifyCommand(command); return { content: [{ type: "text", text: output }] }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [{ type: "text", text: error instanceof Error ? error.message : "Unknown error" }], isError: true }; } }); // Resources and other handlers omitted for brevity - they work the same way // The key lazy loading is implemented in the tools handler above // Enhanced resources handler with comprehensive site data server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: "netlify://sites", name: "List all Netlify sites", description: "Get a comprehensive list of all sites with metadata", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/overview", name: "Site overview", description: "Complete site overview with functions, deployments, and analytics", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/functions", name: "Site functions", description: "List all functions for a specific site", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/env", name: "Environment variables", description: "List environment variables by context", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/deploys", name: "Deploy history", description: "Recent deployments with statistics", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/deploys/{deployId}", name: "Deploy details", description: "Detailed information about a specific deployment", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/forms", name: "Form submissions", description: "Form submissions and configuration", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/analytics", name: "Site analytics", description: "Site usage analytics and performance metrics", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/logs", name: "Site logs", description: "Recent site and function logs", mimeType: "application/json", }, { uri: "netlify://account/usage", name: "Account usage", description: "Account-level usage statistics and limits", mimeType: "application/json", }, { uri: "netlify://account/teams", name: "Team information", description: "Team membership and permissions", mimeType: "application/json", }, { uri: "netlify://status", name: "Netlify service status", description: "Current Netlify service status and health", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/edge-functions", name: "Edge functions", description: "List and manage edge functions for a site", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/build-hooks", name: "Build hooks", description: "Manage build hooks and webhook configurations", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/domains", name: "Site domains", description: "Custom domains and DNS configuration", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/redirects", name: "Site redirects", description: "URL redirects and rewrite rules", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/headers", name: "Custom headers", description: "Custom HTTP headers configuration", mimeType: "application/json", }, { uri: "netlify://blobs/{storeName}", name: "Blob storage", description: "Netlify Blobs storage management", mimeType: "application/json", }, { uri: "netlify://blobs/{storeName}/{key}", name: "Blob data", description: "Individual blob data and metadata", mimeType: "application/json", }, { uri: "netlify://recipes", name: "Available recipes", description: "Netlify automation recipes and templates", mimeType: "application/json", }, { uri: "netlify://recipes/{recipeName}", name: "Recipe details", description: "Detailed recipe configuration and steps", mimeType: "application/json", }, { uri: "netlify://api/methods", name: "API methods", description: "Available Netlify API endpoints and methods", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/performance", name: "Performance metrics", description: "Site performance analytics and optimization data", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/security", name: "Security analysis", description: "Security headers, SSL, and vulnerability analysis", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/bandwidth", name: "Bandwidth usage", description: "Site bandwidth consumption and analytics", mimeType: "application/json", }, { uri: "netlify://sites/{siteId}/errors", name: "Error logs", description: "Site error logs and exception tracking", mimeType: "application/json", }, { uri: "netlify://account/billing", name: "Billing information", description: "Account billing details and usage costs", mimeType: "application/json", }, { uri: "netlify://account/members", name: "Team members", description: "Team member management and permissions", mimeType: "application/json", }, { uri: "netlify://account/integrations", name: "Account integrations", description: "Connected services and integrations", mimeType: "application/json", }, { uri: "netlify://account/tokens", name: "Access tokens", description: "Personal access tokens and API keys", mimeType: "application/json", }, { uri: "netlify://account/notifications", name: "Notification settings", description: "Email and webhook notification preferences", mimeType: "application/json", }, { uri: "netlify://global/regions", name: "Deployment regions", description: "Available deployment regions and edge locations", mimeType: "application/json", }, ], }; }); // Enhanced resource reader with comprehensive data handling server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; try { if (uri === "netlify://sites") { const sites = await siteManager.getSites(); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ sites, count: sites.length, lastUpdated: new Date().toISOString(), }, null, 2), }, ], }; } if (uri.startsWith("netlify://sites/")) { const uriParts = uri.split('/'); const siteId = uriParts[2]; const resource = uriParts[3]; const subResource = uriParts[4]; switch (resource) { case "overview": { const site = await siteManager.getSiteById(siteId); if (!site) { throw new Error(`Site ${siteId} not found`); } try { const [functions, deploys, env] = await Promise.allSettled([ executeNetlifyCommand(`functions:list --json`, siteId), executeNetlifyCommand(`api listSiteDeploys --data='{"site_id":"${siteId}","per_page":5}'`), executeNetlifyCommand(`env:list --json`, siteId), ]); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ site, functions: functions.status === 'fulfilled' ? JSON.parse(functions.value) : [], recentDeploys: deploys.status === 'fulfilled' ? JSON.parse(deploys.value) : [], environmentVariables: env.status === 'fulfilled' ? JSON.parse(env.value) : [], lastUpdated: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ site, error: "Partial data available - some features may require authentication", lastUpdated: new Date().toISOString(), }, null, 2), }, ], }; } } case "functions": { try { const command = `functions:list --json`; const output = await executeNetlifyCommand(command, siteId); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch functions data", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "env": { try { const command = `env:list --json`; const output = await executeNetlifyCommand(command, siteId); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch environment variables", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "deploys": { if (subResource) { // Specific deploy const deployId = subResource; try { const command = `api getDeploy --data='{"deploy_id":"${deployId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Deploy not found or access restricted", deployId, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } else { // List deploys try { const command = `api listSiteDeploys --data='{"site_id":"${siteId}","per_page":10}'`; const output = await executeNetlifyCommand(command); const deploys = JSON.parse(output); // Add deploy statistics const deployStats = { total: deploys.length, successful: deploys.filter((d: any) => d.state === 'ready').length, failed: deploys.filter((d: any) => d.state === 'error').length, building: deploys.filter((d: any) => d.state === 'building').length, }; return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ deploys, statistics: deployStats, total: deploys.length, lastUpdated: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch deploys data", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } case "forms": { try { const command = `api listSiteForms --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch forms data", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "analytics": { try { const command = `api getSiteAnalytics --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Analytics data not available or access restricted", message: "This feature may require a paid plan", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "logs": { try { const command = `functions:logs --json`; const output = await executeNetlifyCommand(command, siteId); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch logs", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "edge-functions": { try { const command = `functions:list --json --edge`; const output = await executeNetlifyCommand(command, siteId); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch edge functions", message: "Edge functions may not be available for this site", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "build-hooks": { try { const command = `api listSiteBuildHooks --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch build hooks", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "domains": { try { const command = `api getSiteDomains --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch domains", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "redirects": { try { const command = `api getSiteRedirects --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch redirects", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "headers": { try { const command = `api getSiteHeaders --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch headers configuration", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "performance": { try { const command = `api getSitePerformance --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Performance data not available", message: "Performance analytics may require a paid plan", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "security": { try { const command = `api getSiteSecurity --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Security data not available", message: "Security analysis may require additional configuration", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "bandwidth": { try { const command = `api getSiteBandwidth --data='{"site_id":"${siteId}"}'`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Bandwidth data not available", message: "Bandwidth analytics may require a paid plan", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "errors": { try { const command = `functions:logs --json --level=error`; const output = await executeNetlifyCommand(command, siteId); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch error logs", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } } // Handle blob storage resources if (uri.startsWith("netlify://blobs/")) { const uriParts = uri.split('/'); const storeName = uriParts[2]; const key = uriParts[3]; if (key) { // Get specific blob try { const command = `blob:get ${storeName} ${key}`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ store: storeName, key, data: output, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch blob", store: storeName, key, message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } else { // List blobs in store try { const command = `blob:list ${storeName}`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ store: storeName, blobs: output.split('\n').filter(line => line.trim()), timestamp: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to list blobs", store: storeName, message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } // Handle recipe resources if (uri.startsWith("netlify://recipes")) { const uriParts = uri.split('/'); const recipeName = uriParts[2]; if (recipeName) { // Get specific recipe details try { const command = `recipes:list --json`; const output = await executeNetlifyCommand(command); const recipes = JSON.parse(output); const recipe = recipes.find((r: any) => r.name === recipeName); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ recipe: recipe || null, found: !!recipe, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch recipe details", recipe: recipeName, message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } else { // List all recipes try { const command = `recipes:list --json`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch recipes", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } // Handle API methods resource if (uri === "netlify://api/methods") { try { const command = `api help --json`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch API methods", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } // Handle account-level resources if (uri.startsWith("netlify://account/")) { const resource = uri.split('/')[2]; switch (resource) { case "usage": { try { const command = `api getAccountUsage`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Usage data not available", message: "Account usage data may require authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "teams": { try { const command = `api listAccountTeams`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Team data not available", message: "Team information may require authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "billing": { try { const command = `api getAccountBilling`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Billing data not available", message: "Billing information requires authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "members": { try { const command = `api listAccountMembers`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Member data not available", message: "Team member information requires authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "integrations": { try { const command = `api listAccountIntegrations`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Integration data not available", message: "Integration information requires authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "tokens": { try { const command = `api listAccessTokens`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Token data not available", message: "Access token information requires authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } case "notifications": { try { const command = `api getNotificationSettings`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Notification settings not available", message: "Notification settings require authentication", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } } // Handle global resources if (uri.startsWith("netlify://global/")) { const resource = uri.split('/')[2]; switch (resource) { case "regions": { try { const command = `api getDeploymentRegions`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: output, }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Region data not available", message: "Deployment region information may not be accessible", timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } } } // Handle status resource if (uri === "netlify://status") { try { const command = `status`; const output = await executeNetlifyCommand(command); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ status: output, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } catch (error) { return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Unable to fetch status", message: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }, null, 2), }, ], }; } } throw new Error(`Resource not found: ${uri}`); } catch (error) { console.error(`Error loading resource ${uri}:`, error); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ error: "Resource loading failed", message: error instanceof Error ? error.message : 'Unknown error', uri, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } }); // Enhanced prompts handler with comprehensive workflow templates server.setRequestHandler(ListPromptsRequestSchema, async () => { return { prompts: [ { name: "netlify-deploy", description: "Complete deployment workflow with validation and monitoring", arguments: [ { name: "path", description: "Site directory path", required: true, }, { name: "production", description: "Deploy to production", required: false, }, { name: "message", description: "Deploy message", required: false, }, ], }, { name: "netlify-setup", description: "Complete site setup workflow", arguments: [ { name: "siteName", description: "Name for the new site", required: true, }, { name: "buildCommand", description: "Build command (default: npm run build)", required: false, }, { name: "publishDir", description: "Publish directory (default: build)", required: false, }, ], }, { name: "netlify-environment-setup", description: "Environment configuration across contexts", arguments: [ { name: "siteId", description: "Site ID to configure", required: true, }, { name: "environment", description: "Target environment (development, staging, production)", required: true, }, ], }, { name: "netlify-troubleshoot", description: "Comprehensive issue diagnosis and resolution", arguments: [ { name: "siteId", description: "Site ID to troubleshoot", required: true, }, { name: "issueType", description: "Type of issue (deployment, build, functions, performance)", required: false, }, ], }, { name: "netlify-function-deploy", description: "Function deployment with best practices", arguments: [ { name: "functionPath", description: "Functions directory path", required: true, }, { name: "runtime", description: "Function runtime (default: nodejs)", required: false, }, ], }, { name: "netlify-migration", description: "Site migration with optimization", arguments: [ { name: "sourceType", description: "Source platform (github-pages, vercel, heroku, etc.)", required: true, }, { name: "repositoryUrl", description: "Repository URL", required: false, }, ], }, { name: "netlify-optimization", description: "Performance, security, and SEO optimization", arguments: [ { name: "siteId", description: "Site ID to optimize", required: true, }, { name: "focusArea", description: "Optimization focus (performance, security, seo, all)", required: false, }, ], }, { name: "netlify-security-audit", description: "Complete security audit and hardening", arguments: [ { name: "siteId", description: "Site ID to audit", required: true, }, { name: "includeHeaders", description: "Include headers analysis (default: true)", required: false, }, ], }, { name: "netlify-performance-audit", description: "Comprehensive performance analysis and optimization", arguments: [ { name: "siteId", description: "Site ID to analyze", required: true, }, { name: "auditType", description: "Type of audit (speed, core-vitals, lighthouse, all)", required: false, }, ], }, { name: "netlify-edge-functions-setup", description: "Edge functions deployment and configuration", arguments: [ { name: "siteId", description: "Site ID for edge functions", required: true, }, { name: "functionType", description: "Edge function type (middleware, api, transform)", required: false, }, ], }, { name: "netlify-blobs-management", description: "Comprehensive blob storage management workflow", arguments: [ { name: "storeName", description: "Blob store name", required: true, }, { name: "operation", description: "Operation type (setup, migrate, optimize, cleanup)", required: false, }, ], }, { name: "netlify-forms-setup", description: "Form handling and submission management setup", arguments: [ { name: "siteId", description: "Site ID for form setup", required: true, }, { name: "formType", description: "Form type (contact, newsletter, survey, custom)", required: false, }, ], }, { name: "netlify-analytics-dashboard", description: "Analytics dashboard setup and monitoring", arguments: [ { name: "siteId", description: "Site ID for analytics", required: true, }, { name: "timeframe", description: "Analysis timeframe (day, week, month, year)", required: false, }, ], }, { name: "netlify-domain-setup", description: "Custom domain configuration and DNS management", arguments: [ { name: "siteId", description: "Site ID for domain setup", required: true, }, { name: "domain", description: "Custom domain to configure", required: true, }, ], }, { name: "netlify-redirects-config", description: "URL redirects and rewrite rules configuration", arguments: [ { name: "siteId", description: "Site ID for redirects", required: true, }, { name: "configType", description: "Configuration type (migration, seo, maintenance)", required: false, }, ], }, { name: "netlify-build-optimization", description: "Build process optimization and caching", arguments: [ { name: "siteId", description: "Site ID to optimize", required: true, }, { name: "buildType", description: "Build optimization focus (speed, caching, dependencies)", required: false, }, ], }, { name: "netlify-monitoring-setup", description: "Comprehensive monitoring and alerting setup", arguments: [ { name: "siteId", description: "Site ID for monitoring", required: true, }, { name: "alertType", description: "Alert type (uptime, performance, errors, all)", required: false, }, ], }, { name: "netlify-backup-strategy", description: "Site backup and disaster recovery planning", arguments: [ { name: "siteId", description: "Site ID for backup strategy", required: true, }, { name: "backupType", description: "Backup type (full, incremental, critical-only)", required: false, }, ], }, { name: "netlify-team-collaboration", description: "Team workflow and collaboration setup", arguments: [ { name: "teamId", description: "Team ID for collaboration setup", required: true, }, { name: "workflowType", description: "Workflow type (gitflow, feature-branch, continuous)", required: false, }, ], }, { name: "netlify-api-integration", description: "API integration and webhook configuration", arguments: [ { name: "siteId", description: "Site ID for API integration", required: true, }, { name: "integrationType", description: "Integration type (cms, analytics, notifications)", required: false, }, ], }, { name: "netlify-staging-workflow", description: "Staging environment and preview deployment workflow", arguments: [ { name: "siteId", description: "Site ID for staging setup", required: true, }, { name: "stagingType", description: "Staging type (branch-previews, deploy-previews, staging-site)", required: false, }, ], }, { name: "netlify-seo-optimization", description: "SEO optimization and search engine visibility", arguments: [ { name: "siteId", description: "Site ID for SEO optimization", required: true, }, { name: "seoFocus", description: "SEO focus area (meta-tags, performance, structure, content)", required: false, }, ], }, { name: "netlify-cdn-optimization", description: "CDN and edge network optimization", arguments: [ { name: "siteId", description: "Site ID for CDN optimization", required: true, }, { name: "optimizationType", description: "Optimization type (caching, compression, regional)", required: false, }, ], }, { name: "netlify-compliance-audit", description: "Compliance and accessibility audit", arguments: [ { name: "siteId", description: "Site ID for compliance audit", required: true, }, { name: "complianceType", description: "Compliance standard (wcag, gdpr, hipaa, pci)", required: false, }, ], }, { name: "netlify-cost-optimization", description: "Cost analysis and optimization recommendations", arguments: [ { name: "accountId", description: "Account ID for cost analysis", required: true, }, { name: "timeframe", description: "Analysis timeframe (month, quarter, year)", required: false, }, ], }, { name: "netlify-disaster-recovery", description: "Disaster recovery testing and procedures", arguments: [ { name: "siteId", description: "Site ID for disaster recovery planning", required: true, }, { name: "recoveryType", description: "Recovery scenario (data-loss, service-outage, security-breach)", required: false, }, ], }, { name: "netlify-advanced-deployment", description: "Advanced deployment strategies and blue-green deployments", arguments: [ { name: "siteId", description: "Site ID for advanced deployment", required: true, }, { name: "strategy", description: "Deployment strategy (blue-green, canary, rolling, instant)", required: false, }, ], }, ], }; }); // Enhanced prompt handler with comprehensive workflow execution server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case "netlify-deploy": { const path = args?.path as string; const production = Boolean(args?.production); const message = args?.message as string; return { description: `Complete deployment workflow for ${path}`, messages: [ { role: "user", content: { type: "text", text: `Please execute a comprehensive deployment workflow for the site at "${path}". **Deployment Configuration:** - **Path:** ${path} - **Production:** ${production} - **Message:** ${message || "Automated deployment"} **Deployment Workflow:** 1. **Pre-deployment Validation:** - Verify site directory exists and contains build artifacts - Check for build configuration files (package.json, netlify.toml) - Validate environment variables are properly set - Run pre-deployment security checks 2. **Build Process Verification:** - Check if build process completed successfully - Verify all required files are present in the deployment directory - Validate asset optimization and compression - Check for any build warnings or errors 3. **Deployment Execution:** - Deploy site: netlify_deploy_site with path "${path}", prod: ${production}, message: "${message}" - Monitor deployment progress and logs - Track deployment metrics and performance 4. **Post-deployment Verification:** - Verify site is accessible and functioning correctly - Run automated tests on the deployed site - Check for any deployment errors or warnings - Validate all functions and integrations are working 5. **Performance & Security Validation:** - Run performance analysis on the deployed site - Check security headers and SSL configuration - Validate SEO optimization and meta tags - Monitor for any runtime errors 6. **Monitoring Setup:** - Configure deployment notifications - Set up monitoring alerts for the site - Document deployment details and changes - Create deployment summary report Please execute this comprehensive deployment workflow and provide detailed feedback at each step.`, }, }, ], }; } case "netlify-setup": { const siteName = args?.siteName as string; const buildCommand = args?.buildCommand as string || "npm run build"; const publishDir = args?.publishDir as string || "build"; return { description: `Complete site setup for ${siteName}`, messages: [ { role: "user", content: { type: "text", text: `Please execute a comprehensive site setup workflow for "${siteName}". **Site Configuration:** - **Site Name:** ${siteName} - **Build Command:** ${buildCommand} - **Publish Directory:** ${publishDir} **Setup Workflow:** 1. **Initial Site Creation:** - Create new site: netlify_create_site with name "${siteName}" - Link current directory: netlify_link_site - Verify connection and site details 2. **Build Configuration:** - Set build command: "${buildCommand}" - Configure publish directory: "${publishDir}" - Validate build process locally 3. **Environment Setup:** - Set up development environment variables - Configure production environment variables - Set up staging environment if needed 4. **Testing & Validation:** - Run initial test build: netlify_build_site - Deploy preview version for testing - Verify all functionality works correctly 5. **Production Setup:** - Configure production domain settings - Set up SSL certificates - Configure security headers and policies 6. **Monitoring & Maintenance:** - Set up deployment notifications - Configure monitoring and analytics - Document deployment process Please execute this comprehensive setup workflow and provide detailed feedback at each step.`, }, }, ], }; } case "netlify-security-audit": { const siteId = args?.siteId as string; const includeHeaders = Boolean(args?.includeHeaders) || true; return { description: `Security audit for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please perform a comprehensive security audit for site "${siteId}". **Include Headers Analysis:** ${includeHeaders} **Security Audit Workflow:** 1. **Initial Security Assessment:** - Get site information: netlify_get_site_info for ${siteId} - Review current security configuration - Analyze access controls and permissions - Document current security posture 2. **Configuration Security Review:** - Audit environment variables and secrets - Review function permissions and scopes - Check build and deploy security settings - Validate authentication configurations ${includeHeaders ? ` 3. **Security Headers Analysis:** - Check Content Security Policy (CSP) headers - Verify HTTPS and HSTS configuration - Analyze X-Frame-Options and X-Content-Type-Options - Review referrer policy and permissions policy ` : ''} 4. **Access Control Audit:** - Review site access permissions - Check form handling and input validation - Verify function authentication and authorization - Analyze API endpoint security 5. **Data Protection Review:** - Audit sensitive data handling - Check encryption at rest and in transit - Review data retention and deletion policies - Validate privacy and compliance requirements 6. **Vulnerability Assessment:** - Check for known security vulnerabilities - Analyze dependencies for security issues - Test for common web application vulnerabilities - Review third-party integrations and services 7. **Incident Response Preparation:** - Review monitoring and alerting systems - Check backup and recovery procedures - Validate incident response plans - Test security event detection and response 8. **Recommendations and Remediation:** - Provide detailed security recommendations - Implement critical security fixes - Set up ongoing security monitoring - Create security maintenance procedures Please execute this comprehensive security audit for site "${siteId}" and provide a detailed security report with actionable recommendations.`, }, }, ], }; } case "netlify-performance-audit": { const siteId = args?.siteId as string; const auditType = args?.auditType as string || "all"; return { description: `Performance audit for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please perform a comprehensive performance audit for site "${siteId}". **Audit Type:** ${auditType} **Performance Audit Workflow:** 1. **Site Performance Baseline:** - Get current site analytics: netlify_get_analytics for ${siteId} - Analyze current performance metrics - Document baseline performance indicators - Review historical performance trends 2. **Core Web Vitals Analysis:** - Measure Largest Contentful Paint (LCP) - Analyze First Input Delay (FID) - Check Cumulative Layout Shift (CLS) - Review First Contentful Paint (FCP) 3. **Build Performance Review:** - Analyze build times and optimization - Review bundle sizes and asset optimization - Check code splitting and lazy loading - Validate caching strategies 4. **Function Performance Analysis:** - Review function execution times - Analyze cold start performance - Check function memory usage - Optimize function code and dependencies 5. **CDN and Edge Performance:** - Analyze CDN cache hit rates - Review edge function performance - Check global distribution effectiveness - Optimize asset delivery strategies 6. **Performance Optimization Implementation:** - Implement critical performance fixes - Optimize images and assets - Configure advanced caching - Set up performance monitoring Please execute this performance audit and provide optimization recommendations for site "${siteId}".`, }, }, ], }; } case "netlify-edge-functions-setup": { const siteId = args?.siteId as string; const functionType = args?.functionType as string || "middleware"; return { description: `Edge functions setup for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up edge functions for site "${siteId}". **Function Type:** ${functionType} **Edge Functions Setup Workflow:** 1. **Edge Functions Environment Preparation:** - Verify site supports edge functions - Check current edge function configuration - Review available runtime options - Set up development environment 2. **Function Development and Configuration:** - Create edge function structure - Configure function routing and triggers - Set up environment variables and secrets - Implement function logic and handlers 3. **Testing and Validation:** - Test edge functions locally - Validate function performance and behavior - Check edge location deployment - Test function integration with site 4. **Deployment and Monitoring:** - Deploy edge functions to production - Set up function monitoring and logging - Configure performance alerts - Monitor function execution and errors Please execute this edge functions setup for site "${siteId}" with focus on ${functionType} functionality.`, }, }, ], }; } case "netlify-blobs-management": { const storeName = args?.storeName as string; const operation = args?.operation as string || "setup"; return { description: `Blob storage management for store ${storeName}`, messages: [ { role: "user", content: { type: "text", text: `Please manage blob storage for store "${storeName}". **Operation:** ${operation} **Blob Storage Management Workflow:** 1. **Storage Assessment:** - List current blobs: netlify_list_blobs for ${storeName} - Analyze storage usage and patterns - Review data organization and structure - Check access patterns and performance 2. **Storage Optimization:** - Optimize blob organization and naming - Implement data lifecycle policies - Configure access controls and permissions - Set up backup and retention strategies 3. **Performance Optimization:** - Analyze blob access patterns - Optimize data retrieval strategies - Configure caching for frequently accessed data - Implement efficient data management 4. **Monitoring and Maintenance:** - Set up storage monitoring and alerts - Configure automated cleanup procedures - Implement data integrity checks - Monitor storage costs and usage Please execute this blob storage management workflow for store "${storeName}" with operation type "${operation}".`, }, }, ], }; } case "netlify-forms-setup": { const siteId = args?.siteId as string; const formType = args?.formType as string || "contact"; return { description: `Forms setup for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up form handling for site "${siteId}". **Form Type:** ${formType} **Forms Setup Workflow:** 1. **Form Configuration:** - Get current forms: netlify_get_form_submissions for ${siteId} - Configure form handling and validation - Set up form fields and data types - Configure submission processing 2. **Form Security and Validation:** - Implement form security measures - Set up spam protection and filtering - Configure input validation and sanitization - Implement CSRF protection 3. **Submission Management:** - Configure submission storage and retrieval - Set up notification and alert systems - Implement automated response handling - Configure data export and backup 4. **Integration and Automation:** - Set up third-party integrations - Configure automated workflows - Implement submission analytics - Set up performance monitoring Please execute this forms setup for site "${siteId}" with form type "${formType}".`, }, }, ], }; } case "netlify-analytics-dashboard": { const siteId = args?.siteId as string; const timeframe = args?.timeframe as string || "month"; return { description: `Analytics dashboard for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up analytics dashboard for site "${siteId}". **Timeframe:** ${timeframe} **Analytics Dashboard Workflow:** 1. **Analytics Data Collection:** - Get site analytics: netlify_get_analytics for ${siteId} - Collect performance metrics and user data - Analyze traffic patterns and behavior - Review conversion and engagement metrics 2. **Dashboard Configuration:** - Set up key performance indicators (KPIs) - Configure data visualization and charts - Implement real-time monitoring - Set up automated reporting 3. **Advanced Analytics:** - Implement custom event tracking - Set up funnel and cohort analysis - Configure A/B testing analytics - Analyze user journey and behavior 4. **Reporting and Insights:** - Generate comprehensive analytics reports - Provide actionable insights and recommendations - Set up automated alert systems - Configure stakeholder dashboards Please execute this analytics dashboard setup for site "${siteId}" with ${timeframe} timeframe analysis.`, }, }, ], }; } case "netlify-domain-setup": { const siteId = args?.siteId as string; const domain = args?.domain as string; return { description: `Domain setup for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please configure custom domain "${domain}" for site "${siteId}". **Domain Setup Workflow:** 1. **Domain Configuration:** - Configure custom domain for site ${siteId} - Set up DNS records and configuration - Verify domain ownership and setup - Configure domain redirects and aliases 2. **SSL and Security Setup:** - Configure SSL certificates for domain - Set up HTTPS redirects and enforcement - Implement security headers and policies - Configure domain security measures 3. **Performance Optimization:** - Configure CDN and edge caching for domain - Set up performance optimization - Implement asset optimization - Configure global distribution 4. **Monitoring and Maintenance:** - Set up domain monitoring and alerts - Configure uptime monitoring - Implement automated renewals - Set up domain analytics Please execute this domain setup for "${domain}" on site "${siteId}".`, }, }, ], }; } case "netlify-redirects-config": { const siteId = args?.siteId as string; const configType = args?.configType as string || "migration"; return { description: `Redirects configuration for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please configure URL redirects for site "${siteId}". **Configuration Type:** ${configType} **Redirects Configuration Workflow:** 1. **Redirect Analysis:** - Analyze current site structure and URLs - Identify redirect requirements and patterns - Review SEO implications and strategies - Plan redirect implementation strategy 2. **Redirect Implementation:** - Configure URL redirects and rewrites - Set up pattern-based redirects - Implement conditional redirects - Configure status codes and parameters 3. **SEO and Performance Optimization:** - Optimize redirects for SEO preservation - Minimize redirect chains and loops - Configure canonical URLs and meta tags - Implement performance-optimized redirects 4. **Testing and Validation:** - Test all redirect rules and patterns - Validate redirect performance and behavior - Check for redirect loops and errors - Monitor redirect analytics and metrics Please execute this redirects configuration for site "${siteId}" with configuration type "${configType}".`, }, }, ], }; } case "netlify-build-optimization": { const siteId = args?.siteId as string; const buildType = args?.buildType as string || "speed"; return { description: `Build optimization for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please optimize build process for site "${siteId}". **Build Type:** ${buildType} **Build Optimization Workflow:** 1. **Build Analysis:** - Analyze current build configuration - Review build times and performance - Identify optimization opportunities - Document current build pipeline 2. **Build Process Optimization:** - Optimize build commands and scripts - Configure build caching strategies - Implement parallel build processes - Optimize dependency management 3. **Asset and Code Optimization:** - Implement code splitting and optimization - Configure asset compression and minification - Optimize images and media assets - Implement tree shaking and dead code elimination 4. **Build Monitoring and Maintenance:** - Set up build performance monitoring - Configure build alerts and notifications - Implement automated optimization checks - Monitor build costs and resource usage Please execute this build optimization for site "${siteId}" with focus on ${buildType} optimization.`, }, }, ], }; } case "netlify-monitoring-setup": { const siteId = args?.siteId as string; const alertType = args?.alertType as string || "all"; return { description: `Monitoring setup for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up comprehensive monitoring for site "${siteId}". **Alert Type:** ${alertType} **Monitoring Setup Workflow:** 1. **Monitoring Infrastructure:** - Set up site health monitoring - Configure uptime and availability checks - Implement performance monitoring - Set up error tracking and logging 2. **Alert Configuration:** - Configure alert thresholds and triggers - Set up notification channels and recipients - Implement escalation procedures - Configure alert suppression and grouping 3. **Performance Monitoring:** - Monitor site performance metrics - Track function execution and errors - Monitor build and deploy processes - Implement user experience monitoring 4. **Analytics and Reporting:** - Set up monitoring dashboards - Configure automated reports - Implement trend analysis and insights - Set up monitoring data retention Please execute this monitoring setup for site "${siteId}" with alert type "${alertType}".`, }, }, ], }; } case "netlify-backup-strategy": { const siteId = args?.siteId as string; const backupType = args?.backupType as string || "full"; return { description: `Backup strategy for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please implement backup strategy for site "${siteId}". **Backup Type:** ${backupType} **Backup Strategy Workflow:** 1. **Backup Assessment:** - Identify critical site data and assets - Analyze backup requirements and schedules - Review data retention and compliance needs - Plan backup and recovery procedures 2. **Backup Implementation:** - Set up automated backup processes - Configure backup storage and retention - Implement incremental and differential backups - Set up backup validation and testing 3. **Disaster Recovery Planning:** - Create disaster recovery procedures - Implement recovery testing and validation - Set up emergency response protocols - Configure backup monitoring and alerts 4. **Backup Maintenance:** - Monitor backup processes and status - Implement backup optimization - Maintain backup documentation - Regular recovery testing and validation Please execute this backup strategy for site "${siteId}" with backup type "${backupType}".`, }, }, ], }; } case "netlify-team-collaboration": { const teamId = args?.teamId as string; const workflowType = args?.workflowType as string || "gitflow"; return { description: `Team collaboration setup for team ${teamId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up team collaboration workflow for team "${teamId}". **Workflow Type:** ${workflowType} **Team Collaboration Workflow:** 1. **Team Setup and Permissions:** - Configure team member roles and permissions - Set up access controls and security - Implement collaboration tools and processes - Configure team communication channels 2. **Development Workflow:** - Set up version control and branching strategy - Configure code review and approval processes - Implement continuous integration and deployment - Set up development environment standards 3. **Project Management:** - Configure project tracking and management - Set up task assignment and monitoring - Implement milestone and deadline tracking - Configure reporting and analytics 4. **Quality Assurance:** - Set up testing and validation procedures - Configure automated quality checks - Implement code quality standards - Set up performance and security testing Please execute this team collaboration setup for team "${teamId}" with workflow type "${workflowType}".`, }, }, ], }; } case "netlify-api-integration": { const siteId = args?.siteId as string; const integrationType = args?.integrationType as string || "cms"; return { description: `API integration for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up API integration for site "${siteId}". **Integration Type:** ${integrationType} **API Integration Workflow:** 1. **API Assessment and Planning:** - Analyze integration requirements and goals - Review available APIs and methods: netlify_list_api_methods - Plan integration architecture and strategy - Configure API authentication and security 2. **Integration Implementation:** - Implement API connections and endpoints - Configure data synchronization and processing - Set up error handling and retry logic - Implement API rate limiting and optimization 3. **Testing and Validation:** - Test API integration functionality - Validate data flow and processing - Check error handling and edge cases - Perform load testing and optimization 4. **Monitoring and Maintenance:** - Set up API monitoring and alerting - Configure integration analytics and reporting - Implement automated maintenance procedures - Monitor API costs and usage Please execute this API integration for site "${siteId}" with integration type "${integrationType}".`, }, }, ], }; } case "netlify-staging-workflow": { const siteId = args?.siteId as string; const stagingType = args?.stagingType as string || "branch-previews"; return { description: `Staging workflow for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please set up staging workflow for site "${siteId}". **Staging Type:** ${stagingType} **Staging Workflow Setup:** 1. **Staging Environment Configuration:** - Configure staging site and environment - Set up branch-based deployments - Configure preview deployment settings - Set up staging-specific configurations 2. **Workflow Implementation:** - Configure automated staging deployments - Set up review and approval processes - Implement staging validation and testing - Configure promotion to production 3. **Testing and Quality Assurance:** - Set up automated testing in staging - Configure performance and security testing - Implement user acceptance testing - Set up staging monitoring and alerts 4. **Deployment and Release Management:** - Configure release management processes - Set up deployment validation and rollback - Implement blue-green deployment strategies - Configure release documentation and tracking Please execute this staging workflow setup for site "${siteId}" with staging type "${stagingType}".`, }, }, ], }; } case "netlify-seo-optimization": { const siteId = args?.siteId as string; const seoFocus = args?.seoFocus as string || "all"; return { description: `SEO optimization for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please optimize SEO for site "${siteId}". **SEO Focus:** ${seoFocus} **SEO Optimization Workflow:** 1. **SEO Analysis and Assessment:** - Analyze current SEO performance and metrics - Review site structure and content optimization - Check technical SEO implementation - Analyze competitor SEO strategies 2. **Technical SEO Optimization:** - Optimize site structure and navigation - Configure meta tags and structured data - Implement canonical URLs and redirects - Optimize site speed and performance 3. **Content and On-page SEO:** - Optimize content for target keywords - Implement semantic markup and schema - Optimize images and media for SEO - Configure internal linking and structure 4. **Monitoring and Reporting:** - Set up SEO monitoring and tracking - Configure search console and analytics - Implement SEO performance reporting - Monitor rankings and organic traffic Please execute this SEO optimization for site "${siteId}" with focus on ${seoFocus}.`, }, }, ], }; } case "netlify-cdn-optimization": { const siteId = args?.siteId as string; const optimizationType = args?.optimizationType as string || "caching"; return { description: `CDN optimization for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please optimize CDN configuration for site "${siteId}". **Optimization Type:** ${optimizationType} **CDN Optimization Workflow:** 1. **CDN Performance Analysis:** - Analyze current CDN performance and metrics - Review cache hit rates and distribution - Check edge location performance - Analyze content delivery patterns 2. **Caching Strategy Optimization:** - Configure optimal caching policies - Implement cache invalidation strategies - Set up edge-side includes and processing - Optimize asset delivery and compression 3. **Global Distribution Optimization:** - Configure regional optimization settings - Implement geo-targeted content delivery - Optimize for mobile and low-bandwidth users - Configure adaptive content delivery 4. **Monitoring and Performance:** - Set up CDN monitoring and analytics - Configure performance alerts and thresholds - Implement automated optimization - Monitor CDN costs and usage Please execute this CDN optimization for site "${siteId}" with optimization type "${optimizationType}".`, }, }, ], }; } case "netlify-compliance-audit": { const siteId = args?.siteId as string; const complianceType = args?.complianceType as string || "gdpr"; return { description: `Compliance audit for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please perform compliance audit for site "${siteId}". **Compliance Type:** ${complianceType} **Compliance Audit Workflow:** 1. **Compliance Assessment:** - Review current compliance status and requirements - Analyze data handling and privacy practices - Check accessibility and usability standards - Review legal and regulatory requirements 2. **Implementation and Remediation:** - Implement required compliance measures - Configure privacy controls and consent management - Set up accessibility features and standards - Implement data protection and security measures 3. **Documentation and Procedures:** - Create compliance documentation and policies - Set up audit trails and logging - Implement compliance training and procedures - Configure compliance monitoring and reporting 4. **Validation and Certification:** - Validate compliance implementation - Perform compliance testing and verification - Obtain necessary certifications and approvals - Set up ongoing compliance monitoring Please execute this compliance audit for site "${siteId}" with compliance type "${complianceType}".`, }, }, ], }; } case "netlify-cost-optimization": { const accountId = args?.accountId as string; const timeframe = args?.timeframe as string || "month"; return { description: `Cost optimization for account ${accountId}`, messages: [ { role: "user", content: { type: "text", text: `Please analyze and optimize costs for account "${accountId}". **Timeframe:** ${timeframe} **Cost Optimization Workflow:** 1. **Cost Analysis:** - Analyze current billing and usage patterns - Review resource consumption and costs - Identify cost optimization opportunities - Benchmark against industry standards 2. **Usage Optimization:** - Optimize bandwidth and storage usage - Configure efficient build and deployment processes - Implement resource usage monitoring - Optimize function execution and costs 3. **Plan and Feature Optimization:** - Review current plan and feature usage - Identify unused or underutilized features - Configure optimal plan and add-ons - Implement cost allocation and tracking 4. **Cost Monitoring and Reporting:** - Set up cost monitoring and alerts - Configure budget tracking and controls - Implement cost reporting and analytics - Set up automated cost optimization Please execute this cost optimization for account "${accountId}" with ${timeframe} analysis.`, }, }, ], }; } case "netlify-disaster-recovery": { const siteId = args?.siteId as string; const recoveryType = args?.recoveryType as string || "data-loss"; return { description: `Disaster recovery for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please implement disaster recovery for site "${siteId}". **Recovery Type:** ${recoveryType} **Disaster Recovery Workflow:** 1. **Risk Assessment and Planning:** - Identify potential disaster scenarios and risks - Analyze recovery requirements and objectives - Plan disaster recovery procedures and protocols - Configure backup and redundancy systems 2. **Recovery Implementation:** - Implement disaster recovery procedures - Set up automated recovery processes - Configure failover and redundancy systems - Test recovery procedures and validation 3. **Incident Response:** - Create incident response procedures - Set up emergency communication channels - Implement escalation and coordination procedures - Configure incident tracking and documentation 4. **Recovery Testing and Maintenance:** - Perform regular disaster recovery testing - Validate recovery procedures and times - Maintain recovery documentation and procedures - Update recovery plans and configurations Please execute this disaster recovery setup for site "${siteId}" with recovery type "${recoveryType}".`, }, }, ], }; } case "netlify-advanced-deployment": { const siteId = args?.siteId as string; const strategy = args?.strategy as string || "blue-green"; return { description: `Advanced deployment for site ${siteId}`, messages: [ { role: "user", content: { type: "text", text: `Please implement advanced deployment strategy for site "${siteId}". **Strategy:** ${strategy} **Advanced Deployment Workflow:** 1. **Deployment Strategy Setup:** - Configure ${strategy} deployment strategy - Set up deployment environments and infrastructure - Configure deployment automation and orchestration - Implement deployment validation and testing 2. **Progressive Deployment:** - Configure canary and progressive deployments - Set up feature flags and gradual rollout - Implement automated rollback and recovery - Configure deployment monitoring and metrics 3. **Validation and Testing:** - Set up automated deployment testing - Configure performance and health checks - Implement user acceptance testing - Set up deployment validation gates 4. **Monitoring and Optimization:** - Configure deployment monitoring and analytics - Set up deployment performance tracking - Implement deployment optimization - Monitor deployment success rates and metrics Please execute this advanced deployment setup for site "${siteId}" with strategy "${strategy}".`, }, }, ], }; } default: throw new Error(`Unknown prompt: ${name}`); } }); // Resource subscription handlers for real-time updates server.setRequestHandler(SubscribeRequestSchema, async (request) => { const { uri } = request.params; try { subscriptions.add(uri); console.error(`[${new Date().toISOString()}] Subscribed to resource: ${uri}`); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ subscribed: true, uri, timestamp: new Date().toISOString(), }), }, ], }; } catch (error) { console.error(`[${new Date().toISOString()}] Subscription error for ${uri}:`, error); throw new Error(`Failed to subscribe to resource: ${uri}`); } }); server.setRequestHandler(UnsubscribeRequestSchema, async (request) => { const { uri } = request.params; try { subscriptions.delete(uri); console.error(`[${new Date().toISOString()}] Unsubscribed from resource: ${uri}`); return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify({ unsubscribed: true, uri, timestamp: new Date().toISOString(), }), }, ], }; } catch (error) { console.error(`[${new Date().toISOString()}] Unsubscription error for ${uri}:`, error); throw new Error(`Failed to unsubscribe from resource: ${uri}`); } }); // Enhanced server startup with SSE and stdio transport support async function main() { try { // Check for SSE transport mode const useSSE = process.env.MCP_TRANSPORT === 'sse' || process.argv.includes('--sse'); const ssePort = parseInt(process.env.MCP_SSE_PORT || '3000'); if (useSSE) { // Initialize enhanced SSE transport enhancedSSETransport = new EnhancedSSETransport({ port: ssePort, path: '/mcp', enableWebSocket: true, enableCors: true, maxConnections: 100, heartbeatInterval: 30000, compressionLevel: 6, }); // Start SSE transport server await enhancedSSETransport.start(); await server.connect(enhancedSSETransport); console.error(`[${new Date().toISOString()}] Netlify MCP Server (v2.0.0) running on enhanced SSE transport`); console.error(`[${new Date().toISOString()}] SSE Endpoint: http://localhost:${ssePort}/mcp`); console.error(`[${new Date().toISOString()}] WebSocket Endpoint: ws://localhost:${ssePort}/mcp/ws`); console.error(`[${new Date().toISOString()}] Health Check: http://localhost:${ssePort}/health`); console.error(`[${new Date().toISOString()}] Stats Endpoint: http://localhost:${ssePort}/stats`); } else { // Use stdio transport (default) const transport = new StdioServerTransport(); await server.connect(transport); console.error(`[${new Date().toISOString()}] Netlify MCP Server (v2.0.0) running on stdio transport`); } console.error(`[${new Date().toISOString()}] Protocol Version: ${LATEST_PROTOCOL_VERSION}`); console.error(`[${new Date().toISOString()}] LAZY LOADING ENABLED: Tools available without authentication, auth validated on execution`); console.error(`[${new Date().toISOString()}] Available tools: 24 Netlify CLI operations`); console.error(`[${new Date().toISOString()}] Available resources: 12 comprehensive data sources`); console.error(`[${new Date().toISOString()}] Available prompts: 8 workflow templates`); console.error(`[${new Date().toISOString()}] Enhanced features: Analytics, Performance Optimization, Plugin System`); } catch (error) { console.error(`[${new Date().toISOString()}] Failed to start server:`, error); throw error; } } // Graceful shutdown with enhanced transport cleanup process.on('SIGINT', async () => { console.error("[Shutdown] Gracefully shutting down Netlify MCP Server..."); try { // Cleanup enhancement systems await performanceOptimizer.cleanup(); // Close SSE transport if running (this also closes the HTTP server) if (enhancedSSETransport) { await enhancedSSETransport.close(); console.error("[Shutdown] Enhanced SSE transport closed"); } // Close MCP server await server.close(); console.error("[Shutdown] MCP server closed"); console.error("[Shutdown] Netlify MCP Server shutdown complete"); process.exit(0); } catch (error) { console.error("[Shutdown] Error during shutdown:", error); process.exit(1); } }); main().catch((error) => { console.error("Fatal error initializing Netlify MCP Server:", error); process.exit(1); });

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/DynamicEndpoints/Netlify-MCP-Server'

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