Skip to main content
Glama

Netlify MCP Server

Official
by netlify

netlify-project-services

Perform Netlify project operations including managing forms, submissions, visitor access, environment variables, and updating project details through structured requests.

Instructions

Select and run one of the following Netlify operations get-project, get-projects, update-visitor-access-controls, update-forms, get-forms-for-project, manage-form-submissions, update-project-name, manage-env-vars, create-new-project

Input Schema

NameRequiredDescriptionDefault
selectSchemaYes

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "selectSchema": { "anyOf": [ { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "get-project", "type": "string" }, "params": { "additionalProperties": false, "properties": { "siteId": { "type": "string" } }, "required": [ "siteId" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "get-projects", "type": "string" }, "params": { "additionalProperties": false, "properties": { "projectNameSearchValue": { "description": "Search for a project by partial name match", "type": "string" }, "teamSlug": { "type": "string" } }, "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "update-visitor-access-controls", "type": "string" }, "params": { "additionalProperties": false, "properties": { "appliesTo": { "description": "Which project context this rule applies to", "enum": [ "all-projects", "non-production-projects" ], "type": "string" }, "passwordValue": { "type": "string" }, "requirePassword": { "type": "boolean" }, "requireSSOTeamLogin": { "type": "boolean" }, "siteId": { "type": "string" } }, "required": [ "siteId", "appliesTo" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "update-forms", "type": "string" }, "params": { "additionalProperties": false, "properties": { "forms": { "enum": [ "enabled", "disabled" ], "type": "string" }, "siteId": { "type": "string" } }, "required": [ "siteId" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "get-forms-for-project", "type": "string" }, "params": { "additionalProperties": false, "properties": { "formId": { "type": "string" }, "siteId": { "type": "string" } }, "required": [ "siteId" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "manage-form-submissions", "type": "string" }, "params": { "additionalProperties": false, "properties": { "action": { "enum": [ "get-submissions", "delete-submission" ], "type": "string" }, "formId": { "type": "string" }, "limit": { "default": 20, "type": "number" }, "offset": { "default": 0, "type": "number" }, "siteId": { "type": "string" }, "submissionId": { "type": "string" } }, "required": [ "action" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "update-project-name", "type": "string" }, "params": { "additionalProperties": false, "properties": { "name": { "description": "Name must be hyphenated alphanumeric such as \"my-site\" or \"my-site-2\"", "pattern": "^[a-z0-9-]+$", "type": "string" }, "siteId": { "type": "string" } }, "required": [ "siteId", "name" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "manage-env-vars", "type": "string" }, "params": { "additionalProperties": false, "properties": { "deleteEnvVar": { "type": "boolean" }, "envVarIsSecret": { "type": "boolean" }, "envVarKey": { "type": "string" }, "envVarValue": { "type": "string" }, "getAllEnvVars": { "type": "boolean" }, "newVarContext": { "default": "all", "enum": [ "all", "dev", "branch-deploy", "deploy-preview", "production", "branch" ], "type": "string" }, "newVarScopes": { "default": [ "all" ], "items": { "enum": [ "all", "builds", "functions", "runtime", "post_processing" ], "type": "string" }, "type": "array" }, "siteId": { "type": "string" }, "upsertEnvVar": { "type": "boolean" } }, "required": [ "siteId" ], "type": "object" } }, "required": [ "operation", "params" ], "type": "object" }, { "additionalProperties": false, "properties": { "aiAgentName": { "type": "string" }, "llmModelName": { "type": "string" }, "operation": { "const": "create-new-project", "type": "string" }, "params": { "additionalProperties": false, "properties": { "name": { "description": "Name must be hyphenated alphanumeric such as \"my-site\" or \"my-site-2\"", "pattern": "^[a-z0-9-]+$", "type": "string" }, "teamSlug": { "type": "string" } }, "type": "object" } }, "required": [ "operation", "params" ], "type": "object" } ] } }, "required": [ "selectSchema" ], "type": "object" }

Implementation Reference

  • Registers the grouped tool 'netlify-project-services-reader' and 'netlify-project-services-updater' for project domain operations when verboseMode is false. Includes the handler logic that dispatches to individual project tools.
    } else { // Register tools grouped by domain with selector (uses anyOf/union) const paramsSchema = { // @ts-ignore selectSchema: tools.length > 1 ? z.union(tools.map(tool => toSelectorSchema(tool))) : toSelectorSchema(tools[0]) }; const friendlyOperationType = operationType === 'read' ? 'reader' : 'updater'; const toolName = `netlify-${domain}-services-${friendlyOperationType}`; const toolDescription = `Select and run one of the following Netlify ${operationType} operations${readOnlyIndicator} ${toolOperations.join(', ')}`; server.registerTool(toolName, { description: toolDescription, inputSchema: paramsSchema, annotations: { readOnlyHint: operationType === 'read' } }, async (...args) => { checkCompatibility(); try { await getNetlifyAccessToken(remoteMCPRequest); } catch (error: NetlifyUnauthError | any) { if (error instanceof NetlifyUnauthError && remoteMCPRequest) { throw new NetlifyUnauthError(); } return { content: [{ type: "text", text: error?.message || 'Failed to get Netlify token' }], isError: true }; } appendToLog(`${toolName} operation: ${JSON.stringify(args)}`); const selectedSchema = args[0]?.selectSchema as any; if (!selectedSchema) { return { content: [{ type: "text", text: 'Failed to select a valid operation. Retry the MCP operation but select the operation and provide the right inputs.' }] } } const operation = selectedSchema.operation; const subtool = tools.find(subtool => subtool.operation === operation); if (!subtool) { return { content: [{ type: "text", text: 'Agent called the wrong MCP tool for this operation.' }] } } const result = await subtool.cb(selectedSchema.params || {}, {request: remoteMCPRequest, isRemoteMCP: !!remoteMCPRequest}); appendToLog(`${domain} operation result: ${JSON.stringify(result)}`); return { content: [{ type: "text", text: JSON.stringify(result) }] } }); }
  • Defines the selector schema used in the inputSchema of the services tool to choose which project operation to run and its parameters.
    const toSelectorSchema = (domainTool: DomainTool<any>) => { return z.object({ // domain: z.literal(domainTool.domain), operation: z.literal(domainTool.operation), params: domainTool.inputSchema.optional(), llmModelName: z.string().optional(), aiAgentName: z.string().optional() }); }
  • Array of all DomainTool instances for project operations, which are categorized and registered under the project services tools.
    export const projectDomainTools = [ getProjectDomainTool, getProjectsDomainTool, updateVisitorAccessControlsDomainTool, updateFormsDomainTool, getFormsForProjectDomainTool, manageFormSubmissionsDomainTool, updateProjectNameDomainTool, manageEnvVarsDomainTool, createNewProjectDomainTool, ]
  • Helper function that splits project tools into read-only (reader) and write (updater) groups to register separate service tools.
    export const categorizeToolsByReadWrite = (domainTools: DomainTool<any>[]) => { const readOnlyTools = domainTools.filter(tool => tool.toolAnnotations.readOnlyHint === true); const writeTools = domainTools.filter(tool => tool.toolAnnotations.readOnlyHint === false || tool.toolAnnotations.readOnlyHint === undefined); return { readOnlyTools, writeTools }; };

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

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

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

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