MCP tools for widgets
Exact MCP widget arguments, targeting rules, design options, response fields, errors, and draft-only changes.
Use these tools to connect a flow to a widget, set its audience and placement, and edit its design. A widget controls where and how a flow appears; it does not contain the flow's questions or branches. See flow tools for those resources.
MCP widget access and draft changes
Every tool accepts optional project_id (string). If omitted, the server uses the connection's active project or an accessible project it can resolve. Supply the ID explicitly when operating across projects.
The tools follow the shared MCP authorization and project-selection rules. There is no additional per-tool plan requirement. A missing project, inaccessible project, or missing entitlement returns an error rather than another project's data.
Configuration reads use the current draft when one exists, otherwise the published configuration. Create, update, duplicate, and delete save the draft and a configuration snapshot. They do not publish, display a widget, or execute its flow. Invalid configuration returns a validation error. Lookup and mutation errors are MCP errors, not successful resource objects. See publication tools before making the widget live.
Examples below are illustrative, not executed. Requests show MCP tool names and arguments; results show the JSON content, not the surrounding MCP transport envelope. Short result examples are explicitly labeled excerpts.
Widget arguments
create-widget and update-widget share these fields. Only creation requires name. Update requires widget_id and at least one changed field.
| Argument | Type and behavior |
|---|---|
name | String. Internal widget name. |
type | String: modal, bar, toaster, inline, or takeover. Creation default: modal. |
is_enabled | Boolean. Creation default: true. |
flow_id | String identifying the flow. Creation default: no linked flow. On update, explicit null detaches it; omission preserves it. |
frequency | String: startover, immediately, pageview, session, or none. Creation default: session. Returned as whenToAskNext. |
visibility | Object described below. |
options | Design object described below. Nested updates preserve omitted keys. |
visibility
| Property | Type and behavior |
|---|---|
conditions | Recursive logic object or null. A leaf, {"and":[...]}, {"or":[...]}, or {"not":...}. null means all pages; {"or":[]} means none. Creation default: null. See condition tools for leaf arguments and validation. |
placements | Array of ordered inline-placement objects. Each requires nonblank string path, nonblank string selector, and position: before, after, or inside. Optional domain is a bare hostname, at most 253 characters, with no scheme, port, path, or wildcard. Omit it to match any domain. |
areas | String identifying an inline embed area, such as workforge-survey. |
trigger | String. Creation default: exitIntent. The runtime values and default mismatch are described below. |
dismissRule | Object with type: session, duration, or forever. Duration rules also use numeric duration and unit: minutes, hours, days, or weeks. Creation default: {"type":"session"}. |
instantDismiss | Boolean. |
formSubmitSelector | Selector used by the modal formsubmit trigger. The stored schema does not impose a dedicated type rule. |
Placement paths can be exact (/welcome) or wildcard (/blog/*). Exact paths take precedence over wildcard paths, then list order resolves ties. inside appends to the target's children. Domains are saved lowercase.
Audience conditions and visual placement are separate. Preserve returned visibility.conditions unchanged if you are not changing targeting. On update, omitted visibility properties survive; a supplied property replaces that property. In particular, conditions, placements, and dismissRule are not recursively merged. Send placements: [] to clear placements. Inline widgets must retain an embed area or at least one complete placement. Non-inline widgets cannot have nonempty placements; clear them when changing type.
Legacy page-targeting properties (show_on_specific_pages, show_pages, hide_on_specific_pages, hide_pages, isWhitelistEnabled, whitelist, isBlacklistEnabled, blacklist) are rejected. Use conditions instead.
Trigger values and the creation default
The tool's description names exitIntent, scroll, and timed, but the visitor runtime does not recognize those as complete trigger values. New widgets nevertheless default to exitIntent. For a non-inline widget, set a supported trigger explicitly. Saving the default alone does not establish that it will appear.
| Runtime value | Behavior |
|---|---|
immediate | Shows when the widget is eligible. |
exit | Exit intent on desktop; idle-based intent on mobile. |
time_5s | Shows after five seconds. Replace 5 with an integer number of seconds. |
scroll_50pc | Shows at 50% page scroll. Replace 50 with the intended integer percentage. A page too short to scroll shows immediately. |
manual | Waits for the widget's manual link or JavaScript trigger. |
formsubmit | Modal only. Observes website form submission, optionally limited by formSubmitSelector. |
barstatic | Bar only. Shows as a static bar. |
Inline widgets show through their placement rather than waiting for visibility.trigger. A valid trigger still does not bypass audience, dismissal, frequency, or device settings.
options
All properties are optional. Returned options use camelCase. custom_css and display_targets are accepted aliases for customCss and displayTargets. Explicit null resets a nullable override; omission preserves it.
Some older design properties have no type restriction in the production schema. They are marked unconstrained below rather than given an invented enum. Copy their existing values when you are not changing them.
| Property | Schema and purpose |
|---|---|
theme | Unconstrained; creation default plain. |
palette | Light-palette object; fields below. |
paletteDark | Object or null. Same palette fields. With darkMode: auto, overrides light colors for the visitor's dark color scheme. |
darkMode | off or auto. off uses the light palette. |
font | Unconstrained body-font setting. |
headingFont | String or null; null inherits the body font. |
typeScale | s, m, l, or custom. Send actual fontSize values when changing scale. |
fontSize | Typography object; fields below. |
structure | Sizing and spacing object; fields below. |
look | Appearance object; fields below. |
overrides | Object containing only phone and tablet. Device-specific fields are described below. |
customCss | Unconstrained advanced CSS setting; creation default empty string. |
placement | Unconstrained placement setting. |
headerInfo | Object with unconstrained isEnabled, style, imageUrl, title, and subtitle. |
progressBar | Object with unconstrained isEnabled and baseColor. |
displayTargets | Object with phones, desktop, and tablets; all default to true on creation. These properties are unconstrained in the schema. |
style | Object with unconstrained shadowSize. |
backButtonLabel, backButtonEnabled | Unconstrained settings. |
nextButtonLabel, skipButtonLabel | Strings; defaults Next and Skip. |
buttonAnimationTrigger | Unconstrained setting. |
Palette fields
palette accepts these unconstrained base properties: borderColor, contrastColor, backgroundColor, textOnContrastColor, and textOnBackgroundColor. Creation defaults are #e2e8f0, #3b82f6, #ffffff, #ffffff, and #1e293b, respectively. In paletteDark, those five properties must be strings.
Both palettes also accept nullable strings: answerButtonColor, textOnAnswerButtonColor, formFieldColor, formFieldTextColor, formFieldBorderColor, placeholderColor, linkColor, backdropColor, backgroundGradientFrom, backgroundGradientTo, questionHeadingColor, questionTextColor, offerHeadingColor, offerTextColor, headerTitleColor, and headerSubtitleColor. backdropOpacity is a number from 0 to 1 or null.
contrastColor and textOnContrastColor style submit buttons. answerButtonColor and textOnAnswerButtonColor style answers. Null question, offer, and header text-color overrides inherit textOnBackgroundColor.
Typography fields
fontSize accepts unconstrained lineHeight, headlineFontSize, formFieldFontSize, descriptionFontSize, answerButtonFontSize, and submitButtonFontSize.
headingFontWeight, bodyFontWeight, and buttonFontWeight are numbers from 400 to 900 or null. submitButtonFontWeight also accepts theme. headerTitleFontSize and headerSubtitleFontSize are nonnegative pixel strings such as 24px or null; null retains the theme size.
Structure fields
These structure properties are unconstrained: formFieldSpacing, buttonBorderRadius, answerButtonSpacing, containerBorderWidth, containerBorderRadius, and widgetWidth.
These properties accept a nonnegative pixel string or null: submitButtonBorderRadius, fieldBorderRadius, imageHeight, backdropBlur, containerPaddingY, containerPaddingX, titleSpacing, contentSpacing, submitSpacing, and headerSpacing.
buttonLetterSpacing and submitButtonLetterSpacing accept an em string, including negative values, or null. Examples: 0.05em, -0.02em.
Custom padding and content spacing apply with look.density: custom, except on bars. Other density presets ignore them.
Appearance fields
look property | Accepted values |
|---|---|
density | compact, comfortable, spacious, custom, or null |
buttonStyle, submitButtonStyle | solid, outline, ghost, gradient, or null |
buttonSize, submitButtonSize | s, m, l, or null |
buttonFullWidth | Boolean or null |
submitButtonFullWidth | Boolean, theme, or null |
buttonUppercase | Boolean |
submitButtonUppercase | Boolean or null |
buttonHover | darken, lighten, lift, none, or null |
submitButtonHover | The same values, plus theme |
fieldStyle | boxed, underlined, filled, or null |
labelPosition | above, inside, hidden, or null |
borderStyle | solid, dashed, or dotted |
backgroundType | color, gradient, or image |
backgroundGradientAngle | Number from 0 to 360 or null |
backgroundImageUrl | String or null |
imagePosition | top, left, background, or null |
entrance | none, fade, slide, scale, or null |
entranceSpeed | slow, normal, or fast |
stepTransition | slideLeft, slideUp, slideDown, crossfade, zoom, none, or null |
stepTransitionFade | Boolean or null |
closeButtonStyle | icon, circle, text, or null |
closeButtonPosition | left, right, or null |
backButtonStyle | link, button, icon, or null |
skipButtonStyle | link, button, or null |
Answer-button settings and submit-button settings are independent. Nullable submit overrides inherit answer settings; theme selects the theme value where allowed.
Device overrides
overrides.phone and overrides.tablet each accept only fontSize, structure, and look; unknown properties are rejected. Base values apply on desktop.
- Device
fontSizeaccepts all typography fields above. Unlike the base object,lineHeightmust be a number, andheadlineFontSize,formFieldFontSize,descriptionFontSize,answerButtonFontSize, andsubmitButtonFontSizemust be strings. Weight and header-size constraints are unchanged. - Device
structureaccepts all structure fields above. The otherwise unconstrained properties must be strings, exceptwidgetWidth, which also accepts null. Pixel andemconstraints are unchanged. - Device
lookaccepts onlydensity,buttonSize,buttonFullWidth,submitButtonSize, andsubmitButtonFullWidth, with the same constraints as the base object.
A generated-design preview does not rebuild for CSS-only changes. Changes to theme, placement, headerInfo, progressBar, displayTargets, backButtonEnabled, backButtonLabel, or look.labelPosition, look.imagePosition, and look.closeButtonStyle require a rebuilt preview rather than an in-place change to an open generated-design preview.
Returned widget object
Create, update, and duplicate return the saved object: id, name, type, isEnabled, contentId (flow ID or null), whenToAskNext, visibility, and options, with schema defaults and any existing configuration properties. IDs start with wdg_. Arguments use flow_id, but the saved object uses contentId.
Get adds presentation fields. List returns a compact summary instead. Do not copy a whole response into an update request; map the writable arguments above.
Configuration repair fills additional defaults beyond the widget constructor. Missing structure values become containerBorderRadius: "8px", containerBorderWidth: "0px", buttonBorderRadius: "0px", answerButtonSpacing: "8px", and formFieldSpacing: "8px". Missing headline size is 18px for bars/toasters and 24px otherwise; description size is 14px for toasters and 16px otherwise. Answer, form-field, and submit sizes default to 13px, with lineHeight: 1.5. Missing header/progress controls are disabled, header style is left, progress base color is #60a5fa, and shadow size is lg. A toaster with no placement receives right. Supplied options survive repair, so read the saved object rather than assuming it contains only the fields sent.
Newer repair also supplies darkMode: "off", paletteDark: null, headingFont: null, and typeScale: "custom" when missing. Optional palette colors, typography weight/header-size overrides, and advanced spacing overrides default to null. Missing look.density, look.buttonStyle, look.buttonSize, and look.fieldStyle are null rather than an explicit preset; borderStyle, backgroundType, and entranceSpeed default to solid, color, and normal.
list-widgets
List widgets without changing the configuration. The only argument is optional project_id.
Returns an array of {id, name, type, isEnabled, trigger, flowId, flowName, pageTargeting, visibility}. flowId and flowName can be null. pageTargeting is all, none, or conditions; the authoritative rule remains visibility.conditions.
Inline entries also include placements, the same array at visibility.placements, and embedCode when an embed area exists. embedCode is a string to place on your site, not an indication that the tool installed anything. Shared access errors apply; an empty project returns an empty array.
Illustrative request and result:
get-widget
Read the full widget. Requires widget_id (string); optional project_id uses the shared contract.
Returns the widget object plus flowName when a contentId exists, dismissRuleSummary, and resolved names alongside recognized resource IDs. Inline widgets can add embedCode, embedInstructions, and placements. Executable conditions and placement rules are returned unchanged; options is the saved design object, not a presentation summary.
Missing ID returns widget_id is required. An unknown ID returns Widget '…' not found. No draft or live changes occur.
Illustrative request and result excerpt:
create-widget
Create a widget in the draft. Requires name (string). Accepts all shared widget arguments and optional project_id.
Returns the saved widget object. It does not create a flow. An inline widget without an embed area or complete placement fails validation. Invalid options or visibility return Validation error: …; missing name returns name is required. The shared configuration validation also applies.
Illustrative request and result excerpt:
update-widget
Change a widget in the draft. Requires widget_id (string) plus one or more shared widget arguments. Optional project_id uses the shared contract. All omitted values survive. Top-level null values are ignored except flow_id: null, which detaches the flow. Nested nullable option properties retain their reset behavior.
Returns the complete saved widget. A supplied nonempty flow_id must resolve to an existing flow. Unknown IDs return Widget '…' not found. or Flow '…' not found. Use list-flows to see available flows, or create one with create-flow. No changed fields returns No fields provided to update. Visibility and design validation errors use the shared rules.
Illustrative request and result excerpt:
duplicate-widget
Copy a widget into the draft. Requires widget_id (string). Optional new_name (string) defaults to the original name followed by (Copy); optional project_id uses the shared contract.
Returns the copied widget with a fresh wdg_ ID. The flow link, audience rules, placements, and design are copied, not duplicated into new resources. The copy keeps the original enablement setting but does not become live until published.
Missing ID or an unknown widget returns an error. Shared save validation applies.
Illustrative request and result excerpt:
delete-widget
Remove a widget from the draft. Requires widget_id (string); optional project_id uses the shared contract.
Returns {deleted: true, widget_id}. It does not delete the linked flow, questions, or offers. The published widget remains live until the draft deletion is published. Missing ID returns widget_id is required.; an unknown ID returns Widget '…' not found.
Illustrative request and result: