degree-dynamicweb-mcp
The degree-dynamicweb-mcp server provides comprehensive programmatic access to manage a DynamicWeb 10 CMS/PIM instance via its Admin API, enabling full CRUD operations on content, structure, and product data.
Item Type Management
List, get, create, update settings/restrictions, and delete item types (including fields, groups, and restrictions in one call)
Field Management
List, add/update, and delete fields on item types using short aliases (e.g.
text,richtext,image) or full .NET class namesDiscover all available editor types from the live DW instance
Page Management
List, get, create, set field values, and delete pages; list all areas/websites
Paragraph Management
List, get, create, set field values, and delete paragraphs on pages
Product Management
List, get, update, and delete products, including top-level fields, custom fields, and category fields
Apply bulk discounts by percentage across a group or explicit product list
Product Schema (PIM Data Model)
List product field types; create, update, and delete product categories and product fields within categories
File Management
List files in directories (with optional extension filter) and list subdirectories
Delivery API (Read-Only)
Fetch areas, pages, and paragraphs with content from the public DynamicWeb Delivery API
API Discovery & Raw Access
Search the Swagger spec for endpoints by keyword, inspect full request/response schemas, and make raw calls to any Admin API endpoint with flexible body modes (
model,raw,update)
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@degree-dynamicweb-mcp List all item types"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
degree-dynamicweb-mcp
Build and edit a DynamicWeb 10 site by asking for it, instead of clicking through the Admin UI. This is an MCP server: it gives Claude, Cursor, Copilot, or your own agent code 45 tools over the DynamicWeb Admin API - item types, fields, pages, paragraphs, products, and the PIM data model.
"Create an OpeningHours item type with a title and a repeatable list of day/hours rows,
then add it to the Contact page."
→ dw_itemtype_create ×2 (the row type, then the parent with an itemrelation field)
→ dw_itemtype_sync_schema (XML alone does not create the database columns)
→ dw_itemtype_health (confirms every field has a column)
→ dw_paragraph_create + dw_paragraph_set_fieldsThree things make this usable rather than merely possible:
Writes are proved, not assumed. DW answers "ok" whether or not a value was stored, so
set_fieldsreads the item back and returns what it now holds. A typo in a SystemName is an error listing the valid names, not a silent no-op.Schema drift is visible. Deploying item type XML does not touch the database; a field whose column is missing saves without error and keeps nothing.
dw_itemtype_healthreports exactly that.The other ~1800 endpoints are reachable.
dw_api_search→dw_api_endpoint_schema→dw_api_callcovers whatever has no dedicated tool.
Install
Get a token from DynamicWeb Admin: Settings > Developer > API Keys > New, with full access. Then, for Claude Code:
claude mcp add dynamicweb -s project \
--env DW_BASE_URL=https://your-dw-instance \
--env DW_API_TOKEN=your-token \
-- npx -y @degree-as/dynamicweb-mcpAny other client wants the same four values in its config file:
{
"mcpServers": {
"dynamicweb": {
"command": "npx",
"args": ["-y", "@degree-as/dynamicweb-mcp"],
"env": {
"DW_BASE_URL": "https://your-dw-instance",
"DW_API_TOKEN": "your-token"
}
}
}
}Restart the client, then ask it to run dw_area_list - a list of your websites means the URL and token are both good.
Only the path and the top-level key differ.
Client | File | Top-level key |
Claude Code |
|
|
Claude Desktop |
|
|
Cursor |
|
|
Windsurf |
|
|
Cline | its MCP settings UI, or the same JSON |
|
VS Code / Copilot |
|
|
Zed |
|
|
Continue.dev |
|
|
DW_BASE_URL defaults to https://localhost:38547 and is the only optional variable; DW_API_TOKEN is required. Against localhost the server disables TLS verification so DW's self-signed dev certificate is accepted - anywhere else the certificate must be valid.
It is a standard stdio MCP server - tools only, no prompts or sampling - so any framework can spawn it with the four values above. OpenAI Agents SDK (Python):
async with MCPServerStdio(
name="DynamicWeb",
params={
"command": "npx",
"args": ["-y", "@degree-as/dynamicweb-mcp"],
"env": {"DW_BASE_URL": "https://your-dw-instance", "DW_API_TOKEN": "your-token"},
},
cache_tools_list=True,
) as dw:
agent = Agent(name="DW editor", mcp_servers=[dw])The JS SDK's MCPServerStdio is equivalent but wants explicit connect()/close(). LangChain goes through langchain-mcp-adapters; Pydantic AI, Mastra, Vercel AI SDK and n8n each have their own stdio MCP client.
ChatGPT and the OpenAI Responses API do not work yet. They never spawn a local process - OpenAI's servers call your endpoint over HTTP - and this server speaks stdio only. Adding a Streamable HTTP entrypoint is planned; src/server.ts is already transport-agnostic, so the server itself will not change.
Related MCP server: TeamDesk MCP Server
Safety
These tools write to a live CMS. Of the 45, 23 only read, 12 create or update, and 10 destroy data: every _delete, plus dw_itemtype_clean_table, dw_product_bulk_discount (overwrites DefaultPrice across a whole group, no undo), and dw_api_call (the caller picks the endpoint).
Each tool declares MCP annotations - readOnlyHint, destructiveHint, idempotentHint - so a client can warn before a destructive call or auto-approve a read. Whether it does is the client's choice, not this server's. There is no dry-run and no confirmation step here: point it at staging before production.
Tools
45 tools, all prefixed dw_, grouped by the DynamicWeb concept they act on.
Item Types
Tool | Description |
| List all item types |
| Get item type details and restrictions |
| Create item type with fields, groups, and restrictions in one call |
| Update settings (name, category, icon, availability, etc.) |
| Update restrictions (allowed parents, children, websites, etc.) |
| Delete an item type |
Schema maintenance
Deploying item type XML does not touch the database. Until the schema is synced, a field whose column is missing saves without error and keeps nothing.
Tool | Description |
| Report fields whose DB column is missing, and columns the XML no longer declares |
| Reload item type XML and create the missing tables and columns |
| List the pages and paragraphs that use an item type |
| Destructive. Delete orphaned rows from an item type's table |
After deploying new XML: dw_itemtype_sync_schema, then dw_itemtype_health. The sync endpoint answers "ok" even when it aborted partway, so the health check is what tells you whether it worked - and /Files/System/Log/items/ActivationWorkflow holds the real errors. An item type whose table is missing entirely does not appear in the health report at all.
Fields
Tool | Description |
| List fields on an item type |
| Add or update a field |
| Delete a field |
| List all available editor types from the DW instance (not hardcoded) |
Pages
Tool | Description |
| List pages, optionally filtered by area or parent |
| Get a page with all item fields |
| Create a page under a parent |
| Set item field values on a page |
| Delete a page |
| List all areas (websites) |
Paragraphs
Tool | Description |
| List paragraphs on a page |
| Get a paragraph with all item fields |
| Create a paragraph on a page |
| Set item field values on a paragraph |
| Delete a paragraph |
dw_page_set_fields and dw_paragraph_set_fields verify their own write. A field name the item type does not declare is an error that lists the names it does have, and after saving they read the item back and return what it now holds. DW answers "ok" whether or not a value was stored, so a typo in a SystemName used to be indistinguishable from a successful write.
Products
Tool | Description |
| List products, optionally filtered by group or search |
| Get a single product (full model incl. CustomFields/CategoryFields). Returns |
| Update top-level fields, customFields, and categoryFields on a product |
| Delete one or more products |
| Apply a percentage discount to DefaultPrice across a group or product list |
dw_product_update accepts three input maps:
fields- top-level product fields (Name, DefaultPrice, Stock, etc.)customFields- global product custom field values, keyed by SystemNamecategoryFields- product category field values, keyed by SystemName
Product Schema
Manage the PIM data model: product categories (groups of attributes) and product fields (the attributes themselves).
Tool | Description |
| List the 15 product field types (TypeId + aliases) |
| List product categories |
| Create or update a product category |
| Delete categories (3-step DW workflow handled internally) |
| List fields belonging to a category |
| Create or update a field on a category (accepts type aliases) |
| Delete fields from a single category |
Files
Tool | Description |
| List files in a directory, optionally filtered by extension |
| List subdirectories |
Delivery API (read-only)
Tool | Description |
| Fetch areas from Delivery API |
| Fetch pages with content |
| Fetch paragraphs with content |
API Discovery
Tool | Description |
| Search the Swagger spec for endpoints by keyword |
| Get request/response schema for an endpoint |
| Raw call to any Admin API endpoint |
Reference
When creating fields, you can use short aliases instead of full .NET class names:
Alias | Editor |
| TextEditor |
| LongTextEditor |
| RichTextEditor |
| RichTextEditorLight |
| FileEditor |
| FolderEditor |
| MediaEditor |
| LinkEditor |
| ItemLinkEditor |
| ItemRelationListEditor |
| IntegerEditor |
| DecimalEditor |
| DateEditor |
| DateTimeEditor |
| CheckboxEditor |
| CheckboxListEditor |
| DropDownListEditor |
| RadioButtonListEditor |
| EditableListEditor |
| ColorEditor |
| ColorSwatchEditor |
| ItemTypeEditor |
| ItemTypeTabEditor |
| UserEditor |
| SingleUserEditor |
| SingleUserGroupEditor |
| GeolocationEditor |
| GoogleFontEditor |
| HiddenFieldEditor |
| PasswordEditor |
Any full .NET editor class name is also accepted. Use dw_field_types to discover all available editors from your DW instance.
Repeatable lists (itemrelation)
itemrelation (ItemRelationListEditor) creates a repeatable list of child items — the generic way to model FAQ items, rows, persons, etc. (instead of fixed numbered slots like Question1..5). It needs two extra params:
Param | Required | Description |
| yes | systemName of the child item type the list holds. Create it first. |
| no | where items live. Default |
Create the child item type first, then the parent:
// 1) child row
dw_itemtype_create { systemName: "OpeningHoursRow", fields: [
{ name: "Label", systemName: "Label", type: "text" },
{ name: "Value", systemName: "Value", type: "text" },
]}
// 2) parent with the repeatable list
dw_itemtype_create { systemName: "OpeningHours", fields: [
{ name: "Title", systemName: "Title", type: "text" },
{ name: "Rows", systemName: "Rows", type: "itemrelation", itemRelationType: "OpeningHoursRow" },
]}The tool emits the required EditorConfiguration + EditorFields (Item type / Item source) and the Int32 underlying type automatically.
Product fields use a different system - integer TypeId from FieldTypeAll, not editor class names:
Alias | TypeId | Name |
| 1 | Text (255) |
| 2 | Long text |
| 3 | Checkbox |
| 4 | Date |
| 5 | Date/Time |
| 6 | Integer |
| 7 | Decimal |
| 8 | Link |
| 9 | File |
| 10 | Text (100) |
| 11 | Text (50) |
| 12 | Text (20) |
| 13 | Text (5) |
| 14 | Editor |
| 15 | List |
Numeric TypeId is also accepted directly. Use dw_product_field_type_list to fetch the live list from your DW instance.
Symptom | Cause |
|
|
| Token wrong, expired, or from a different instance |
| API key lacks full access - recreate it with broader rights |
|
|
| Remote host with an untrusted certificate, or DW not running |
Tools missing after an upgrade | Client caches the old process - restart it fully |
Development
npm install
npm run dev # tsx, hot reload
npm run build # tsc
npm run start # compiledsrc/
index.ts stdio entrypoint - env, process-level policy, transport
server.ts createServer() - registers every tool, knows no transport
client.ts DwClient - the three DW API calling conventions, documented in its header
utils.ts shared Zod and response helpers
tools/ one module per concept, each exporting registerXTools(server, client)A new tool module means one import and one entry in registrars in server.ts. A new tool needs annotations beside its description, or clients cannot tell whether it writes. The server version comes from package.json, so a release bumps one file. After changes, npm run build and restart your client - clients cache the tool list at startup.
A second transport (Streamable HTTP, for ChatGPT and the Responses API) is a new entrypoint beside index.ts, not a change to server.ts.
Available Tools
41 toolsdw_api_callA
Make a raw call to any DynamicWeb Admin API endpoint. For GET: provide params as query params. For POST: choose bodyMode. - 'model' (default) — wraps your model in {"Model": ...}. Used by most Save endpoints that create new records. - 'raw' — sends your model as the top-level body (no wrapper). Used by delete-style commands (e.g. ProductDelete, ItemTypeDelete). Supports params in the URL. - 'update' — sends {RunUpdateIndex?, QueryData, model} and appends ?Query.Type=queryType. Used to UPDATE existing records via screen commands (e.g. ProductSave). For update mode: pass queryType (e.g. 'ProductById'), queryData (identifies the record: {Id, LanguageId, QueryContext:{screenTypeName:'ProductEdit'}}), and optionally extraFields (e.g. {RunUpdateIndex:true}).
Inputs: endpoint (required), method, params, model, +4 more.
dw_api_endpoint_schemaA
Get the full request/response schema for a specific DynamicWeb Admin API endpoint. Use this before calling an unknown endpoint to understand its parameters.
Inputs: path (required), method.
dw_api_searchA
Search the DynamicWeb Admin API Swagger spec for endpoints matching a keyword. Use this when you're unsure which endpoint to call — search by feature name (e.g. "navigation", "media", "user"). Returns matching paths with their HTTP methods and summaries.
Inputs: keyword (required), maxResults.
dw_area_listB
List all DynamicWeb areas (websites/channels).
Inputs: no named parameters.
dw_content_areasA
Fetch all areas (websites) from DynamicWeb Delivery API. No auth required.
Inputs: no named parameters.
dw_content_pagesB
Fetch pages from DynamicWeb Delivery API. Returns pages with their item fields (content). Use pageId to get a specific page, or areaId to list all pages in a website.
Inputs: pageId, areaId, url, pageSize, +1 more.
dw_content_paragraphsA
Fetch paragraphs (content blocks) from DynamicWeb Delivery API. Returns paragraphs with their item fields. Use pageId to get all paragraphs for a specific page.
Inputs: pageId (required), itemTypeSystemName.
dw_field_deleteC
Delete a field from a DynamicWeb item type.
Inputs: itemTypeSystemName (required), fieldSystemName (required).
dw_field_listA
List all fields for a DynamicWeb item type. Returns systemName, type, required for each field.
Inputs: systemName (required).
dw_field_saveB
Add or update a field on a DynamicWeb item type.
Set isNew: true to add a new field. Set isNew: false to update existing.
IMPORTANT: RichTextEditor requires EditorConfiguration — this tool handles that automatically.Inputs: itemTypeSystemName (required), name (required), systemName (required), type (required), +3 more.
dw_field_typesA
List all available field editor types from this DynamicWeb instance. Fetches the authoritative list from the DW AddIn registry — not hardcoded. Returns full .NET class names and short aliases you can use in dw_field_save and dw_itemtype_create.
Inputs: no named parameters.
dw_files_directoriesC
List subdirectories in a DynamicWeb directory.
Inputs: directoryPath.
dw_files_listB
List files in a DynamicWeb directory. Optionally filter by file extensions.
Inputs: directoryPath, extensions.
dw_itemtype_createA
Create a new DynamicWeb item type with fields and restrictions in one operation.
Category conventions:
- Page item types → category: "" (top-level)
- Layout/config → category: "Layout"
- Article paragraphs → category: "Paragraphs/Article"
- Landing paragraphs → category: "Paragraphs/Landing"
For Page item types, set restrictions.allowedChildItemTypes to the paragraph systemNames that editors can add.
For Paragraph item types, leave restrictions.allowedChildItemTypes empty.Inputs: systemName (required), name (required), description, category, +6 more.
dw_itemtype_deleteC
Delete a DynamicWeb item type by systemName.
Inputs: systemName (required).
dw_itemtype_getA
Get a single DynamicWeb item type by systemName, including all restrictions.
Inputs: systemName (required).
dw_itemtype_listA
List all DynamicWeb item types. Returns systemName, name, category, fieldsCount, enabledFor.
Inputs: no named parameters.
dw_itemtype_update_restrictionsA
Update restrictions on an existing DynamicWeb item type.
Only pass the restriction arrays you want to change — omitted ones are left untouched.
Most common use: adding allowed paragraph types to a Page item type so editors can add content blocks.
Example: allowedChildItemTypes: ["HeroBanner", "RichText", "CTABlock"]Inputs: systemName (required), allowedWebsites, allowedParentTypes, allowedSections, +3 more.
dw_itemtype_update_settingsA
Update Settings fields on an existing DynamicWeb item type. Only pass the fields you want to change — omitted ones are preserved from current state.
Corresponds to the Settings tab in DW Admin (General, Availability, Title for new items, Advanced sections).
Inputs: systemName (required), name, description, category, +8 more.
dw_page_createA
Create a new DynamicWeb page under a parent page.
Steps: 1) Creates blank page via PageCreate 2) Sets name, item type, publication via PageSave.
After creating, use dw_page_set_fields to populate item fields.Inputs: parentPageId (required), name (required), itemType (required), areaId, +3 more.
dw_page_deleteB
Delete a DynamicWeb page by ID. This is irreversible.
Inputs: pageId (required).
dw_page_getB
Get a single DynamicWeb page by ID, including all item fields.
Inputs: pageId (required).
dw_page_listA
List DynamicWeb pages. Filter by areaId (website ID) or parentPageId.
Inputs: areaId, parentPageId.
dw_page_set_fieldsA
Set item fields on a DynamicWeb page.
Fetches the current page, updates field values in its pageItem structure, then saves. fields is a key-value map where keys are field SystemNames and values are the content.
Inputs: pageId (required), fields (required).
dw_paragraph_createA
Create a new paragraph on a DynamicWeb page.
Creates the paragraph via ParagraphSave with the specified item type.
Use dw_paragraph_set_fields after creation to populate content fields.
sort: paragraphs are ordered ascending. Use 100, 200, 300... for easy re-ordering.Inputs: pageId (required), itemType (required), sort, active.
dw_paragraph_deleteB
Delete a DynamicWeb paragraph by ID.
Inputs: paragraphId (required).
dw_paragraph_getA
Get a single DynamicWeb paragraph by ID, including all item fields.
Inputs: paragraphId (required).
dw_paragraph_listC
List paragraphs on a DynamicWeb page.
Inputs: pageId (required).
dw_paragraph_set_fieldsA
Set item fields on a DynamicWeb paragraph.
Fetches the current paragraph, updates field values in its contentItem structure, then saves. fields is a key-value map where keys are field SystemNames and values are the content. For richtext fields, provide HTML string. For file/image fields use the file path string (e.g. "/Files/Images/hero.jpg").
Inputs: paragraphId (required), fields (required).
dw_product_bulk_discountA
Apply a percentage discount to DefaultPrice across a set of products (modifies the base price in-place). Target either a groupId (all products in the group) or an explicit productIds array. Returns per-product old/new price.
Inputs: percent (required), groupId, productIds, languageId, +2 more.
dw_product_category_deleteA
Delete one or more DynamicWeb product categories. Irreversible. Fields belonging to the categories must be deleted first via dw_product_field_delete - otherwise the validation step will reject them.
Internally runs DW's 3-step delete: ProductCategorySetIds (mark candidates) → ProductCategoryDeleteValidated (get valid/invalid split) → ProductCategoryDelete.
Inputs: ids (required).
dw_product_category_listB
List DynamicWeb product categories (groups of product attribute fields). Returns id, name, fieldsCount per category.
Inputs: search, pagingSize, pagingIndex.
dw_product_category_saveA
Create or update a DynamicWeb product category (group of attribute fields). Set isNew: true to create, false to update an existing one. Category fields are added separately via dw_product_field_save with this category's id.
Inputs: id (required), name (required), categoryType, isNew.
dw_product_deleteA
Delete one or more DynamicWeb products. Irreversible. IDs must be in modelIdentifier format: 'PROD1|LANG1|'. The tool accepts plain IDs too and auto-formats them.
Inputs: ids (required), languageId.
dw_product_field_deleteA
Delete one or more product fields from a single category. Irreversible. All ids must belong to the same categoryId. To delete fields across multiple categories, call this tool once per category.
Inputs: categoryId (required), systemNames (required).
dw_product_field_listA
List all product fields belonging to a category. Returns systemName, name, typeId, typeName, required.
Inputs: categoryId (required).
dw_product_field_saveB
Create or update a product field (attribute) on a product category.
Type can be a numeric TypeId or a short alias: text, longtext, checkbox, date, datetime, number, decimal, link, file, richtext, dropdown. Use dw_product_field_type_list for the full mapping.
Field SystemName becomes the key the frontend reads via the product CustomFields/CategoryFields structure.
Inputs: categoryId (required), systemName (required), name (required), type (required), +9 more.
dw_product_field_type_listA
List all DynamicWeb product field types (Text, Integer, Date, etc.) with their TypeId. Use the returned 'id' as TypeId in dw_product_field_save, or use a short alias (text, longtext, checkbox, date, datetime, number, decimal, link, file, richtext, dropdown).
Inputs: no named parameters.
dw_product_getB
Get a single DynamicWeb product by ID. Returns the full model including CustomFields.
Inputs: id (required), languageId, variantId.
dw_product_listA
List DynamicWeb products. Filter by groupId (product catalog group) or search term. Returns id, number, name, defaultPrice, stock, active. Use pagingSize to control result count.
Inputs: groupId, languageId, search, pagingSize, +1 more.
dw_product_updateA
Update fields on an existing DynamicWeb product. Fetches the current product, overlays your field updates, and saves via ProductSave (update mode, Query.Type=ProductById).
'fields': top-level product fields (Name, DefaultPrice, Stock, Active, etc.) - PascalCase or camelCase.
'customFields': global product custom fields, keyed by SystemName (e.g. {Color: "red"}).
'categoryFields': product category fields, keyed by SystemName.
Manage the schema of customFields/categoryFields via dw_product_field_save / dw_product_category_save.
Inputs: id (required), languageId, variantId, fields, +3 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 41 tools
Each tool targets a specific entity and action with clear, distinct purposes; overlaps are minimal and descriptions clarify any ambiguity (e.g., dw_area_list vs dw_content_areas).
All tools follow a consistent 'dw_<domain>_<action>' or 'dw_<domain>_<subdomain>_<action>' pattern in snake_case, making it predictable and easy for agents to infer functionality.
41 tools cover a broad range of CMS and e-commerce operations; while slightly high, each tool serves a distinct purpose and the granularity aids agent selection.
CRUD operations are covered for core entities (item types, pages, paragraphs, products, categories, fields); minor gaps exist (e.g., file upload missing) but the raw API call tool can compensate.
Maintenance
Related MCP Connectors
An MCP server that provides access to Agility CMS. See https://mcp.agilitycms.com for more details.
MCP server for AI access to Swagger by SmartBear.
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for Drupal sites via JSON:API, enabling CRUD operations on nodes, taxonomy terms, and users using natural language.8MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for TeamDesk databases, enabling CRUD operations, search, and document generation via natural language.4MIT
- AlicenseCqualityDmaintenanceMCP server for Shopify Admin API. Enables product, order, customer, and inventory management via natural language.148 npm1MIT
- AlicenseAqualityDmaintenanceMCP server for Microsoft Dynamics 365 Business Central that enables AI assistants to query and manage Business Central data via full CRUD operations.62,547 npmMIT