create_release
Create a new release in a Storyblok space with optional scheduling, branch deployment, and user notifications.
Instructions
Creates a new release in a specified Storyblok space.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of the release | |
| release_at | No | Scheduled release date/time (ISO 8601) | |
| timezone | No | Timezone for the release | |
| branches_to_deploy | No | Branch IDs to deploy to | |
| users_to_notify_ids | No | User IDs to notify |
Implementation Reference
- src/tools/releases.ts:55-84 (handler)The handler for the create_release tool. It constructs a release payload with optional fields (release_at, timezone, branches_to_deploy, users_to_notify_ids), wraps it in { release: ... }, and POSTs to /releases via apiPost(). Returns the JSON response or an APIError.
// Tool: create_release server.tool( 'create_release', 'Creates a new release in a specified Storyblok space.', { name: z.string().describe('Name of the release'), release_at: z.string().optional().describe('Scheduled release date/time (ISO 8601)'), timezone: z.string().optional().describe('Timezone for the release'), branches_to_deploy: z.array(z.number()).optional().describe('Branch IDs to deploy to'), users_to_notify_ids: z.array(z.number()).optional().describe('User IDs to notify'), }, async ({ name, release_at, timezone, branches_to_deploy, users_to_notify_ids }) => { try { const releaseData: Record<string, unknown> = { name }; if (release_at !== undefined) releaseData.release_at = release_at; if (timezone !== undefined) releaseData.timezone = timezone; if (branches_to_deploy !== undefined) releaseData.branches_to_deploy = branches_to_deploy; if (users_to_notify_ids !== undefined) releaseData.users_to_notify_ids = users_to_notify_ids; const payload = { release: releaseData }; const data = await apiPost('/releases', payload); return createJsonResponse(data); } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); - src/tools/releases.ts:59-65 (schema)Zod schema for create_release input: name (string, required), release_at (string, optional), timezone (string, optional), branches_to_deploy (array of numbers, optional), users_to_notify_ids (array of numbers, optional).
{ name: z.string().describe('Name of the release'), release_at: z.string().optional().describe('Scheduled release date/time (ISO 8601)'), timezone: z.string().optional().describe('Timezone for the release'), branches_to_deploy: z.array(z.number()).optional().describe('Branch IDs to deploy to'), users_to_notify_ids: z.array(z.number()).optional().describe('User IDs to notify'), }, - src/tools/index.ts:77-77 (registration)Registration call: registerReleases(server) invoked from the tool aggregator, which registers all release tools including create_release on the MCP server.
registerReleases(server); - src/tools/releases.ts:10-145 (registration)The registerReleases function exported from releases.ts. It calls server.tool('create_release', ...) to register the tool on the MCP server.
export function registerReleases(server: McpServer): void { // Tool: retrieve_multiple_releases server.tool( 'retrieve_multiple_releases', 'Retrieves multiple releases from a specified Storyblok space.', { space_id: z.number().describe('Space ID'), branch_id: z.number().optional().describe('Filter by branch ID'), }, async ({ branch_id }) => { try { const params: Record<string, string> = {}; if (branch_id !== undefined) params.branch_id = String(branch_id); const data = await apiGet('/releases', params); return createJsonResponse(data); } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); // Tool: retrieve_single_release server.tool( 'retrieve_single_release', 'Retrieves a single release from a specified Storyblok space.', { release_id: z.number().describe('ID of the release to retrieve'), }, async ({ release_id }) => { try { const data = await apiGet(`/releases/${release_id}`); return createJsonResponse(data); } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); // Tool: create_release server.tool( 'create_release', 'Creates a new release in a specified Storyblok space.', { name: z.string().describe('Name of the release'), release_at: z.string().optional().describe('Scheduled release date/time (ISO 8601)'), timezone: z.string().optional().describe('Timezone for the release'), branches_to_deploy: z.array(z.number()).optional().describe('Branch IDs to deploy to'), users_to_notify_ids: z.array(z.number()).optional().describe('User IDs to notify'), }, async ({ name, release_at, timezone, branches_to_deploy, users_to_notify_ids }) => { try { const releaseData: Record<string, unknown> = { name }; if (release_at !== undefined) releaseData.release_at = release_at; if (timezone !== undefined) releaseData.timezone = timezone; if (branches_to_deploy !== undefined) releaseData.branches_to_deploy = branches_to_deploy; if (users_to_notify_ids !== undefined) releaseData.users_to_notify_ids = users_to_notify_ids; const payload = { release: releaseData }; const data = await apiPost('/releases', payload); return createJsonResponse(data); } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); // Tool: update_release server.tool( 'update_release', 'Updates an existing release in a specified Storyblok space.', { release_id: z.number().describe('ID of the release to update'), name: z.string().optional().describe('New name for the release'), release_at: z.string().optional().describe('New scheduled release date/time'), timezone: z.string().optional().describe('New timezone'), branches_to_deploy: z.array(z.number()).optional().describe('New branch IDs to deploy to'), users_to_notify_ids: z.array(z.number()).optional().describe('New user IDs to notify'), do_release: z.boolean().optional().describe('Whether to trigger the release'), }, async ({ release_id, name, release_at, timezone, branches_to_deploy, users_to_notify_ids, do_release }) => { try { const releaseData: Record<string, unknown> = {}; if (name !== undefined) releaseData.name = name; if (release_at !== undefined) releaseData.release_at = release_at; if (timezone !== undefined) releaseData.timezone = timezone; if (branches_to_deploy !== undefined) releaseData.branches_to_deploy = branches_to_deploy; if (users_to_notify_ids !== undefined) releaseData.users_to_notify_ids = users_to_notify_ids; const payload: Record<string, unknown> = { release: releaseData }; if (do_release !== undefined) payload.do_release = do_release; const data = await apiPut(`/releases/${release_id}`, payload); return createJsonResponse(data); } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); // Tool: delete_release server.tool( 'delete_release', 'Deletes a release.', { release_id: z.string().describe('ID of the release to delete'), }, async ({ release_id }) => { try { await apiDelete(`/releases/${release_id}`); return { content: [ { type: 'text' as const, text: `Release ${release_id} has been successfully deleted.` }, ], }; } catch (error) { if (error instanceof APIError) { return createErrorResponse(error); } throw error; } } ); } - src/utils/api.ts:195-206 (helper)The apiPost helper used by the handler to make the POST request to the Storyblok Management API.
export async function apiPost<T = unknown>( path: string, body: unknown ): Promise<T> { const url = buildManagementUrl(path); const response = await fetch(url, { method: 'POST', headers: getManagementHeaders(), body: JSON.stringify(body), }); return handleResponse<T>(response, url); }