Skip to main content
Glama

strapi_rest

Execute REST API requests against Strapi CMS endpoints to read, create, update, and delete content. Supports content types, components, filtering, and pagination with user authorization required for write operations.

Instructions

Execute REST API requests against Strapi endpoints. IMPORTANT: All write operations (POST, PUT, DELETE) require explicit user authorization via the userAuthorized parameter.

  1. Reading components: params: { populate: ['SEO'] } // Populate a component params: { populate: { SEO: { fields: ['Title', 'seoDescription'] } } } // With field selection

  2. Updating components (REQUIRES USER AUTHORIZATION): body: { data: { // For single components: componentName: { Title: 'value', seoDescription: 'value' }, // For repeatable components: componentName: [ { field: 'value' } ] } } userAuthorized: true // Must set this to true for POST/PUT/DELETE after getting user permission

  3. Other parameters:

  • fields: Select specific fields

  • filters: Filter results

  • sort: Sort results

  • pagination: Page through results

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
serverNoThe name of the server to connect to
endpointNoThe API endpoint (e.g., 'api/articles')
methodNoHTTP method to useGET
paramsNoOptional query parameters for GET requests. For components, use populate: ['componentName'] or populate: { componentName: { fields: ['field1'] } }
bodyNoRequest body for POST/PUT requests. For components, use: { data: { componentName: { field: 'value' } } } for single components or { data: { componentName: [{ field: 'value' }] } } for repeatable components
userAuthorizedNoREQUIRED for POST/PUT/DELETE operations. Client MUST obtain explicit user authorization before setting this to true.

Implementation Reference

  • The core handler function that executes the strapi_rest tool logic: validates authorization for writes, constructs the request URL with params, makes the fetch call to Strapi, logs performance, and handles the response/error.
    async function makeRestRequest( serverName: string, endpoint: string, method: string = 'GET', params?: Record<string, any>, body?: Record<string, any>, userAuthorized: boolean = false, requestId?: string ): Promise<any> { // Check for write operations that require explicit user authorization if ((method === 'POST' || method === 'PUT' || method === 'DELETE') && !userAuthorized) { throw new McpError( ErrorCode.InvalidParams, `AUTHORIZATION REQUIRED: ${method} operations require explicit user authorization.\n\n` + `IMPORTANT: The client MUST:\n` + `1. Ask the user for explicit permission before making this request\n` + `2. Show the user exactly what data will be modified\n` + `3. Receive clear confirmation from the user\n` + `4. Set userAuthorized=true when making the request\n\n` + `This is a security measure to prevent unauthorized data modifications.` ); } const serverConfig = getServerConfig(serverName); let url = `${serverConfig.API_URL}/${endpoint}`; // Parse query parameters if provided if (params) { const queryString = qs.stringify(params, { encodeValuesOnly: true }); if (queryString) { url = `${url}?${queryString}`; } } const headers = { 'Authorization': `Bearer ${serverConfig.JWT}`, 'Content-Type': 'application/json', }; const requestOptions: RequestInit = { method, headers, }; if (body && (method === 'POST' || method === 'PUT')) { requestOptions.body = JSON.stringify(body); } const startTime = Date.now(); logger.debug(`Making REST request to Strapi`, { requestId, server: serverName, endpoint, method, hasParams: !!params, hasBody: !!body, userAuthorized, url: url.replace(serverConfig.JWT, '[REDACTED]') }); try { const response = await fetch(url, requestOptions); const duration = Date.now() - startTime; logger.logApiCall( requestId || 'unknown', method, endpoint, duration, response.status, serverName ); return await handleStrapiError(response, `REST request to ${endpoint}`, requestId); } catch (error) { const duration = Date.now() - startTime; logger.error(`REST request to ${endpoint} failed`, { requestId, server: serverName, endpoint, method, duration, errorType: error instanceof Error ? error.constructor.name : typeof error }, error instanceof Error ? error : undefined); throw error; } }
  • Zod schema defining input validation for the strapi_rest tool, including server, endpoint, method, params, body, and userAuthorized flag with refinement for write ops.
    const RestSchema = z.object({ server: z.string().min(1, "Server name is required and cannot be empty"), endpoint: z.string().min(1, "Endpoint is required and cannot be empty"), method: z.enum(["GET", "POST", "PUT", "DELETE"], { errorMap: () => ({ message: "Method must be one of: GET, POST, PUT, DELETE" }) }).optional().default("GET"), params: z.union([ z.record(z.any()), z.string().transform((str, ctx) => { try { return JSON.parse(str); } catch (e) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Params must be a valid JSON object or object" }); return z.NEVER; } }) ]).optional(), body: z.union([ z.record(z.any()), z.string().transform((str, ctx) => { try { return JSON.parse(str); } catch (e) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Body must be a valid JSON object or object" }); return z.NEVER; } }) ]).optional(), userAuthorized: z.union([ z.boolean(), z.string().transform((str, ctx) => { if (str === "true") return true; if (str === "false") return false; ctx.addIssue({ code: z.ZodIssueCode.custom, message: "userAuthorized must be boolean true/false or string 'true'/'false'" }); return z.NEVER; }) ]).optional().default(false) }).strict().refine( (data) => { // For write operations, ensure userAuthorized is explicitly set to true if (["POST", "PUT", "DELETE"].includes(data.method) && !data.userAuthorized) { return false; } return true; }, { message: "Write operations (POST, PUT, DELETE) require explicit user authorization (userAuthorized: true)", path: ["userAuthorized"] } );
  • src/index.ts:1288-1344 (registration)
    Tool registration in the ListTools handler: defines name, detailed description with examples, and inputSchema derived from Zod schema.
    name: "strapi_rest", description: "Execute REST API requests against Strapi endpoints. IMPORTANT: All write operations (POST, PUT, DELETE) require explicit user authorization via the userAuthorized parameter.\n\n" + "1. Reading components:\n" + "params: { populate: ['SEO'] } // Populate a component\n" + "params: { populate: { SEO: { fields: ['Title', 'seoDescription'] } } } // With field selection\n\n" + "2. Updating components (REQUIRES USER AUTHORIZATION):\n" + "body: {\n" + " data: {\n" + " // For single components:\n" + " componentName: {\n" + " Title: 'value',\n" + " seoDescription: 'value'\n" + " },\n" + " // For repeatable components:\n" + " componentName: [\n" + " { field: 'value' }\n" + " ]\n" + " }\n" + "}\n" + "userAuthorized: true // Must set this to true for POST/PUT/DELETE after getting user permission\n\n" + "3. Other parameters:\n" + "- fields: Select specific fields\n" + "- filters: Filter results\n" + "- sort: Sort results\n" + "- pagination: Page through results", inputSchema: { ...zodToJsonSchema(ToolSchemas.strapi_rest), properties: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties, server: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.server, description: "The name of the server to connect to" }, endpoint: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.endpoint, description: "The API endpoint (e.g., 'api/articles')" }, method: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.method, description: "HTTP method to use", default: "GET" }, params: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.params, description: "Optional query parameters for GET requests. For components, use populate: ['componentName'] or populate: { componentName: { fields: ['field1'] } }" }, body: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.body, description: "Request body for POST/PUT requests. For components, use: { data: { componentName: { field: 'value' } } } for single components or { data: { componentName: [{ field: 'value' }] } } for repeatable components" }, userAuthorized: { ...zodToJsonSchema(ToolSchemas.strapi_rest).properties.userAuthorized, description: "REQUIRED for POST/PUT/DELETE operations. Client MUST obtain explicit user authorization before setting this to true.", default: false } } },
  • Dispatch handler in CallToolRequestSchema: validates input, extracts params, calls the makeRestRequest handler, and formats response.
    // Validate input using Zod (includes authorization check) const validatedArgs = validateToolInput("strapi_rest", args, requestId); const { server, endpoint, method, params, body, userAuthorized } = validatedArgs; logger.startRequest(requestId, name, server); const data = await makeRestRequest(server, endpoint, method, params, body, userAuthorized, requestId); result = { content: [ { type: "text", text: JSON.stringify(data, null, 2), }, ], };
  • Helper function used by the handler to process Strapi responses, extract errors with hints, log, and throw McpError if failed.
    async function handleStrapiError(response: Response, context: string, requestId?: string): Promise<any> { if (!response.ok) { let errorMessage = `${context} failed with status: ${response.status}`; let errorData: any = null; try { errorData = await response.json() as any; if (errorData && typeof errorData === 'object' && 'error' in errorData) { errorMessage += ` - ${errorData.error?.message || JSON.stringify(errorData.error)}`; // Add helpful hints based on status if (response.status === 400) { errorMessage += "\nHINT: Check the request structure matches Strapi's expectations. For v4/v5 differences, refer to Strapi's migration guide."; } else if (response.status === 404) { errorMessage += "\nHINT: Check the endpoint path and ID are correct."; } } } catch { errorMessage += ` - ${response.statusText}`; } logger.error(`Strapi API error: ${context}`, { requestId, status: response.status, statusText: response.statusText, url: response.url, errorData: errorData, context }); throw new McpError(ErrorCode.InternalError, errorMessage); } logger.debug(`Strapi API success: ${context}`, { requestId, status: response.status, url: response.url }); return response.json(); }

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/misterboe/strapi-mcp-server'

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