Best practices and known patterns for creating displays, symbols, and dashboards via MCP.
Use DisplaysList for creating and editing displays. DisplaysDraw is the Designer visual editor tab — not a writable table. Similarly, use DisplaysSymbols for symbols. Always call get_table_schema('DisplaysList') for the display schema.
Displays use Width and Height properties directly on the display object. Symbols use a Size property with format "Width,Height" (e.g., "400,300"). Do not mix them — Size on a display is ignored, Width/Height on a symbol are ignored.
Every element on a Canvas display needs explicit position:
Left — horizontal offset from left edge (pixels)Top — vertical offset from top edge (pixels)Elements without position stack at (0,0). For a 1920×1080 display, typical layout starts elements at Left=20, Top=20 with spacing.
Dashboard displays use a flat Cells array. Each cell needs:
Column and Row — zero-based grid positionColumnSpan and RowSpan — how many cells to span (default 1)Elements — array of controls within that cell{
"Type": "DashboardDisplay",
"Columns": 3,
"Rows": 2,
"Cells": [
{ "Column": 0, "Row": 0, "Elements": [ ... ] },
{ "Column": 1, "Row": 0, "ColumnSpan": 2, "Elements": [ ... ] }
]
}
Do not create CellGroup, Grid, RowDefinition, or ColumnDefinition objects — those are internal WPF representations. The importer builds them from the flat Cells format.
Some controls are read-only and will be rejected by write_objects. Check the schema — if writeSupported is false, do not include that control. The import will return an error.
Current read-only controls include: Image (use IndustrialIcon or shapes instead), RadioButton, WPF Control, Blazor Control, ToggleButton, MapsESRI, MapsGMap, MapsOSM, FlowPanel.
When a write is rejected, the error message suggests using get_table_schema with the specific control name for alternatives.
Use the IconName property with a human-readable name like "Home", "Valve", "Pump", "Tank", "Motor". Do not set FontFamily, FontSize, or Text — those are internal properties managed by the import pipeline.
Call get_table_schema('IndustrialIcon') to see the full list of available icon names.
LinkedValue is the primary data-binding property for almost every control. It accepts tag paths in the format "Tag.FolderPath/TagName".
For controls that display text (Button, ToggleSwitch, NumericTextBox), set Text for static labels. LinkedValue binds the control's value to a tag.
Exception: BarChart data items use FieldNameValue instead of LinkedValue.
Dynamics add runtime behavior to any element. Each dynamic is a separate JSON object within the element's Dynamicsarray.
{
"Type": "Ellipse",
"Width": 40,
"Height": 40,
"Dynamics": [
{
"Type": "FillColorDynamic",
"LinkedValue": "Tag.Process/Status",
"ChangeColorItems": [
{ "Value": "0", "Color": "Gray" },
{ "Value": "1", "Color": "Green" }
]
}
]
}
Key rules:
get_table_schema for the specific dynamic type to see its exact property namesColorDynamic is abstract — use FillColorDynamic, ForeColorDynamic, or StrokeColorDynamicShineDynamic controls glow/shine effects — it does not have a LinkedValue propertyActionDynamic properties use internal names: ObjectLink, ObjectValueLink, ActionTypeControls with child collections (TrendChart pens, DataGrid columns, PieChart items) use wrapper arrays. The wrapper needs a Type that names the collection class:
{
"Type": "TrendChart",
"Pens": {
"Type": "TrendPenList",
"Items": [
{ "PenName": "Temperature", "TagName": "Tag.Process/Temp" }
]
}
}
Collection types: TrendPenList, PieChartDataList, GridColumnList, ColumnDataList, TimelineColumnList.
Do not set Id on collection items — it is auto-managed by the engine.
To apply a theme color, use the "theme:ColorName" prefix on any color property:
{ "Fill": "theme:Accent1", "Foreground": "theme:Text" }
To clear a theme (revert to explicit color), set the color to any explicit value like "#FF0000" — the engine removes the theme binding automatically.
All shapes require StrokeThickness (default is usually 1 but should be explicit). Common shapes: Ellipse, Rectangle, Line, Polyline, Path, Border.
Use Fill for interior color, Stroke for border/outline color.
Group — groups child elements that move together. Children go in ChildElements array.Border — a container with optional border and background. Single child in Child property.ChildDisplay — embeds another display. Use DisplayName property to reference the target display.The MainPage display (ID=0 in DisplaysList) is the default display every solution starts with. Configure it as the main process overview. The Startup layout (ID=0 in DisplaysLayouts) controls which displays appear on startup.
Use get_table_schema('DisplaysLayouts') for layout structure. Layouts define regions; displays fill those regions.
After calling write_objects, the success response is your primary confirmation. Do not enter a screenshot verification loop. At most, take one screenshot to confirm visual rendering, then deliver your report and let the user review.
If something looks wrong in a screenshot, mention it in the report — do not silently retry or investigate further.