netlify-user-services-reader
Retrieve user account information from Netlify services using read-only operations through the Model Context Protocol.
Instructions
Select and run one of the following Netlify read operations (read-only) get-user
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| selectSchema | Yes |
Implementation Reference
- src/tools/index.ts:139-198 (registration)Registers the "netlify-user-services-reader" tool (read-only grouped operations for user domain). Defines selector schema, tool description, and dispatch handler that authenticates, selects sub-operation (e.g., get-user), executes subtool callback, and returns JSON result.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/user-tools/get-user.ts:8-18 (handler)Subtool handler for 'get-user' operation: calls Netlify API endpoint '/api/v1/user' using getAPIJSONResult helper and returns stringified JSON response.export const getUserDomainTool: DomainTool<typeof getUserParamsSchema> = { domain: 'user', operation: 'get-user', inputSchema: getUserParamsSchema, toolAnnotations: { readOnlyHint: true, }, cb: async (_, {request}) => { return JSON.stringify(await getAPIJSONResult('/api/v1/user', {}, {}, request)); } }
- src/tools/user-tools/index.ts:4-4 (registration)Registers getUserDomainTool in userDomainTools array, imported and used by main tools index to include in netlify-user-services-reader.export const userDomainTools = [getUserDomainTool]
- src/utils/api-networking.ts:142-171 (helper)Helper function getAPIJSONResult performs authenticated API call to Netlify, handles auth errors, parses JSON response. Used by get-user handler for /api/v1/user.export const getAPIJSONResult = async (urlOrPath: string, options: RequestInit = {}, apiInteractionOptions: APIInteractionOptions = {}, incomingRequest?: Request): Promise<any> => { if(!apiInteractionOptions.pagination){ const response = await authenticatedFetch(urlOrPath, options, incomingRequest); if(response.status === 401 && incomingRequest) { throw new NetlifyUnauthError(`Unauthedenticated request to Netlify API. ${urlOrPath}`); } if (!response.ok) { if(apiInteractionOptions.failureCallback){ return apiInteractionOptions.failureCallback(response); } throw new Error(`Failed to fetch API: ${response.status}`); } const data = await response.text(); if (!data) { return ''; } try{ return JSON.parse(data); } catch (e) { if (apiInteractionOptions.failureCallback) { return apiInteractionOptions.failureCallback(response); } return data; } }