Data Pages Tool
data_pages_toolList, retrieve metadata and content, update settings, and edit static text for Webflow pages.
Instructions
Data tool - Pages tool to perform actions like list pages, get page metadata, update page settings, get page content, and update static content
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| actions | Yes |
Implementation Reference
- src/tools/pages.ts:252-287 (handler)The actual handler function for the data_pages_tool - iterates over actions (list_pages, get_page_metadata, update_page_settings, get_page_content, update_static_content) and executes the corresponding helper functions.
async ({ actions }) => { const result: Content[] = []; try { for (const action of actions) { if (action.list_pages) { const content = await listPages(action.list_pages); result.push(textContent(content)); } if (action.get_page_metadata) { const content = await getPageMetadata(action.get_page_metadata); result.push(textContent(content)); } if (action.update_page_settings) { const content = await updatePageSettings( action.update_page_settings ); result.push(textContent(content)); } if (action.get_page_content) { const content = await getPageContent(action.get_page_content); result.push(textContent(content)); } if (action.update_static_content) { const content = await updateStaticContent( action.update_static_content ); result.push(textContent(content)); } } return toolResponse(result); } catch (error) { return formatErrorResponse(error); } } ); } - src/tools/pages.ts:20-108 (handler)Five helper handler functions (listPages, getPageMetadata, updatePageSettings, getPageContent, updateStaticContent) that make the actual Webflow API calls for the data_pages_tool.
const listPages = async (arg: { site_id: string; localeId?: string; limit?: number; offset?: number; }) => { const response = await getClient().pages.list( arg.site_id, { localeId: arg.localeId, limit: arg.limit, offset: arg.offset, }, requestOptions ); return response; }; const getPageMetadata = async (arg: { page_id: string; localeId?: string; }) => { const response = await getClient().pages.getMetadata( arg.page_id, { localeId: arg.localeId, }, requestOptions ); return response; }; const updatePageSettings = async (arg: { page_id: string; localeId?: string; body: z.infer<typeof WebflowPageSchema>; }) => { const { seo, openGraph, slug, title, ...rest } = arg.body; const pageSettings = { ...(seo && { seo }), ...(openGraph && { openGraph }), ...(slug && { slug }), ...(title && { title }), }; const response = await getClient().pages.updatePageSettings( arg.page_id, { localeId: arg.localeId, ...pageSettings, body: { ...rest, ...pageSettings }, }, requestOptions ); return response; }; const getPageContent = async (arg: { page_id: string; localeId?: string; limit?: number; offset?: number; }) => { const response = await getClient().pages.getContent( arg.page_id, { localeId: arg.localeId, limit: arg.limit, offset: arg.offset, }, requestOptions ); return response; }; const updateStaticContent = async (arg: { page_id: string; localeId: string; nodes: any; }) => { const response = await getClient().pages.updateStaticContent( arg.page_id, { localeId: arg.localeId, nodes: arg.nodes, }, requestOptions ); return response; }; - src/tools/pages.ts:110-287 (registration)Registration of the 'data_pages_tool' via server.registerTool() including metadata (title, description, annotations) and the input schema with all five possible actions.
server.registerTool( "data_pages_tool", { title: "Data Pages Tool", annotations: { readOnlyHint: false, }, description: "Data tool - Pages tool to perform actions like list pages, get page metadata, update page settings, get page content, and update static content", inputSchema: { actions: z.array( z .object({ // GET https://api.webflow.com/v2/sites/:site_id/pages list_pages: z .object({ site_id: z .string() .describe("The site's unique ID, used to list its pages."), localeId: z .string() .optional() .describe( "Unique identifier for a specific locale. Applicable when using localization." ), limit: z .number() .optional() .describe( "Maximum number of records to be returned (max limit: 100)" ), offset: z .number() .optional() .describe( "Offset used for pagination if the results have more than limit records." ), }) .optional() .describe( "List all pages within a site. Returns page metadata including IDs, titles, and slugs." ), // GET https://api.webflow.com/v2/pages/:page_id get_page_metadata: z .object({ page_id: z .string() .describe("Unique identifier for the page."), localeId: z .string() .optional() .describe( "Unique identifier for a specific locale. Applicable when using localization." ), }) .optional() .describe( "Get metadata for a specific page including SEO settings, Open Graph data, and page status (draft/published)." ), // PUT https://api.webflow.com/v2/pages/:page_id update_page_settings: z .object({ page_id: z .string() .describe("Unique identifier for the page."), localeId: z .string() .optional() .describe( "Unique identifier for a specific locale. Applicable when using localization." ), body: WebflowPageSchema, }) .optional() .describe( "Update page settings including SEO metadata, Open Graph data, slug, and publishing status." ), // GET https://api.webflow.com/v2/pages/:page_id/dom get_page_content: z .object({ page_id: z .string() .describe("Unique identifier for the page."), localeId: z .string() .optional() .describe( "Unique identifier for a specific locale. Applicable when using localization." ), limit: z .number() .optional() .describe( "Maximum number of records to be returned (max limit: 100)" ), offset: z .number() .optional() .describe( "Offset used for pagination if the results have more than limit records." ), }) .optional() .describe( "Get the content structure and data for a specific page including all elements and their properties for localization." ), // POST https://api.webflow.com/v2/pages/:page_id/dom update_static_content: z .object({ page_id: z .string() .describe("Unique identifier for the page."), localeId: z .string() .describe( "Unique identifier for a specific locale. Applicable when using localization." ), nodes: WebflowPageDomWriteNodesItemSchema, }) .optional() .describe( "Update content on a static page in secondary locales by modifying text nodes and property overrides." ), }) .strict() .refine( (d) => [ d.list_pages, d.get_page_metadata, d.update_page_settings, d.get_page_content, d.update_static_content, ].filter(Boolean).length >= 1, { message: "Provide at least one of list_pages, get_page_metadata, update_page_settings, get_page_content, update_static_content.", } ) ), }, }, async ({ actions }) => { const result: Content[] = []; try { for (const action of actions) { if (action.list_pages) { const content = await listPages(action.list_pages); result.push(textContent(content)); } if (action.get_page_metadata) { const content = await getPageMetadata(action.get_page_metadata); result.push(textContent(content)); } if (action.update_page_settings) { const content = await updatePageSettings( action.update_page_settings ); result.push(textContent(content)); } if (action.get_page_content) { const content = await getPageContent(action.get_page_content); result.push(textContent(content)); } if (action.update_static_content) { const content = await updateStaticContent( action.update_static_content ); result.push(textContent(content)); } } return toolResponse(result); } catch (error) { return formatErrorResponse(error); } } ); } - src/mcp.ts:56-56 (registration)Registration call in the main MCP server setup - registerPagesTools(server, getClient) wires up the data_pages_tool into the server.
registerPagesTools(server, getClient); - Zod schema for WebflowPage used as the 'body' parameter type in the update_page_settings action of the data_pages_tool.
export const WebflowPageSchema = z.object({ id: z.string().describe("Unique identifier for a Page."), siteId: z.string().optional().describe("Unique identifier for the Site."), title: z.string().optional().describe("Title of the page."), slug: z .string() .optional() .describe("Slug of the page (derived from title)."), parentId: z .string() .optional() .describe("Unique identifier for the parent folder."), collectionId: z .string() .optional() .describe( "Unique identifier for the linked collection, NULL id the Page is not part of a collection." ), createdOn: z.date().optional().describe("Date when the page was created."), lastUpdated: z .date() .optional() .describe("Date when the page was last updated."), archived: z .boolean() .optional() .describe("Indicates if the page is archived."), draft: z.boolean().optional().describe("Indicates if the page is a draft."), canBranch: z .boolean() .optional() .describe("Indicates if the page can be branched."), isBranch: z .boolean() .optional() .describe("Indicates if the page is Branch of another page."), isMembersOnly: z .boolean() .optional() .describe( "Indicates whether the Page is restricted by Memberships Controls." ), seo: z .object({ title: z .string() .optional() .describe("The Page title shown in search engine results."), description: z .string() .optional() .describe("The Page description shown in search engine results."), }) .optional() .describe("SEO-related fields for the page."), openGraph: z .object({ title: z .string() .optional() .describe("The title supplied to Open Graph annotations."), titleCopied: z .boolean() .optional() .describe( "Indicates the Open Graph title was copied from the SEO title." ), description: z .string() .optional() .describe("The description supplied to Open Graph annotations."), descriptionCopied: z .boolean() .optional() .describe( "Indicates the Open Graph description was copied from the SEO description." ), }) .optional(), localeId: z .string() .optional() .describe( "Unique identifier for the page locale. Applicable when using localization." ), publishedPath: z .string() .optional() .describe("Relative path of the published page."), });