netlify-project-services-reader
Retrieve Netlify project details, list projects, or access form data for specific sites using the Netlify MCP Server's read operations.
Instructions
Select and run one of the following Netlify read operations (read-only) get-project, get-projects, get-forms-for-project
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| selectSchema | Yes |
Implementation Reference
- src/tools/index.ts:154-197 (handler)Handler function for the 'netlify-project-services-reader' tool. It authenticates with Netlify, parses the selected sub-operation from input, finds the corresponding read-only project tool, executes its callback, and returns the JSON-stringified result.}, 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) }] } });
- src/tools/index.ts:138-198 (registration)Registration block for grouped domain tools. For domain='project' and operationType='read', registers 'netlify-project-services-reader' with selector schema over read-only project tools.// 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) }] } }); }
- src/tools/index.ts:139-142 (schema)Input schema definition for netlify-project-services-reader: a selector (selectSchema) that is a union over each read-only project tool's operation + params schema.const paramsSchema = { // @ts-ignore selectSchema: tools.length > 1 ? z.union(tools.map(tool => toSelectorSchema(tool))) : toSelectorSchema(tools[0]) };
- Array of all project domain tools. Read-only ones (those with toolAnnotations.readOnlyHint=true, like get-project and get-projects) are grouped under netlify-project-services-reader.export const projectDomainTools = [ getProjectDomainTool, getProjectsDomainTool, updateVisitorAccessControlsDomainTool, updateFormsDomainTool, getFormsForProjectDomainTool, manageFormSubmissionsDomainTool, updateProjectNameDomainTool, manageEnvVarsDomainTool, createNewProjectDomainTool, ]
- Sub-handler (cb function) for the 'get-project' operation, executed by netlify-project-services-reader when selected.export const getProjectDomainTool: DomainTool<typeof getProjectParamsSchema> = { domain: 'project', operation: 'get-project', inputSchema: getProjectParamsSchema, toolAnnotations: { readOnlyHint: true, }, cb: async ({ siteId }, {request}) => { return JSON.stringify(getEnrichedSiteModelForLLM(await getAPIJSONResult(`/api/v1/sites/${siteId}`, {}, {}, request))); } }