MCP server that teaches AI agents to build Dominion Dashboard Enhanced Apps (plugin format v2 — runtime plugin.json + optional sandboxed adapter.js). Synced to Dominion 2.1.0-beta.
16 tools with strong naming (all verb-prefixed: get_*, scaffold_*, validate_*, preview_*, create_*) and comprehensive descriptions (avg 180 chars, well above 10-char minimum). All tools have input schemas with type definitions. However, 12 knowledge tools (get_*) have empty input objects {}, making their schemas trivial. Output schemas are not explicitly documented in the visible code. Error handling is present but recovery guidance is minimal. Tool composition is excellent, clear single responsibilities and proper chaining (scaffold → validate → preview → package). Security is good (no secrets in params, read-only risk annotations). Descriptions are LLM-optimized and include prerequisites and workflow context.
Validate then package a plugin into an upload-ready ZIP on disk. Files are placed under a top-level folder equal to the manifest id (folder name must equal id). Refuses to package if validation fails. Returns the absolute ZIP path to hand to the user for Einstellungen > Community Apps > Upload.
Interactive tiles: declare manifest.actions, execute via api.actions (No-Code) or exports.executeAction (adapter.js), and place "button" widget nodes. Server-side execution, confirm dialogs, params with validation, rate limits, refresh behavior.
[Data path 2: code] The adapter.js sandbox: required/optional exports (fetchStats, testConnection, crawlEntities, checkNotifications), the exact available/forbidden globals, timeouts, and the guardedFetch SSRF/size rules. Use for login flows, multiple requests, or computed values.
Exact runtime TypeScript contracts a plugin must honor: ConfigField, StatOption, StatItem, PluginStats, categories, tile sizes, OAuth config, and the entity crawler. Read before writing plugin.json or adapter.js.
Packaging, ZIP upload via Einstellungen > Community Apps, runtime-loader behavior (PLUGINS_DIR, hot-load, no restart), catalog API, and v1->v2 migration.
Knowledge tools (12x get_*) have empty input schemas ({}). While appropriate for read-only discovery tools, output schemas are not documented in visible code, forcing LLMs to infer response structure.
Error handling in validate_manifest and create_plugin_zip returns validation errors but lacks recovery guidance. E.g., 'missing apiUrl field' should suggest 'Add configFields with key=apiUrl and type=url'.
scaffold_plugin and preview_widget accept string parameters for complex JSON objects (pluginJson, widget, sampleContext). No validation of JSON syntax before processing; malformed input will fail at parse time with generic errors.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Two complete gold-standard example plugins to copy and adapt: pi-hole (No-Code api block + widget) and qbittorrent (adapter.js login/cookie flow + widget). Verbatim from docs/examples.
The formal JSON Schema (draft-07) for plugin.json, verbatim from docs/schemas/plugin.schema.json. Use it to machine-validate a manifest or to drive generation.
[READ BEFORE configFields] The app lifecycle AFTER upload: install -> add tile -> config modal (where credentials are collected — required:true matters!) -> testConnection -> encrypted save -> first fetchStats -> states (error/unconfigured) -> reconfigure. Prevents the classic 'credentials never asked' bug.
Full field reference for plugin.json (format v2): required/optional fields, the api-vs-adapter data-source rule, and the mandatory apiUrl config field.
How notifications and the notification API work: plugin-side checkNotifications + notificationRules (rule/tag matching, dedup), the PluginNotification shape, AND the external POST /api/notifications HTTP API (headers, body, responses, rate limits) for scripts/N8N/webhooks.
[Data path 1: No-Code] The plugin.json "api" block: RestApiSpec/RestEndpoint/RestStatMapping, {config.*} templating, dot-path mapping, format semantics (number/bytes/percent/duration/raw), and widgetData. Use for simple JSON HTTP APIs — no code.
[START HERE] Orientation for building a Dominion Enhanced App plugin (format v2): folder layout, the two data-source paths (No-Code api vs adapter.js), tile roles, golden rules, and the full agent workflow. Call this first.
The declarative widget Baukasten for 2x1/2x2 tiles: all 9 node types (stats, gauge, progress, sparkline, text, list, carousel, row, column), bindings, template strings, showIf, and nesting limits. No React.
Render a declarative widget to a glass-dark HTML preview (approximation of the dashboard WidgetRenderer) and write it to disk. Supply the widget node JSON plus a sampleContext ({ stats:{items:[...]}, widgetData:{...}, config:{...} }) so bindings resolve. Great for a quick visual sanity check before packaging.
Generate a correct skeleton plugin.json + optional adapter.js stub based on the app's name, description, data-source choice (No-Code api vs adapter.js), auth type, stat keys, and widget preferences. Fills in boilerplate so the agent can focus on the logic.
Validate a plugin.json object against the v2 rules: required fields, types, kebab-case ids, color format, configFields (including mandatory apiUrl), statOptions, supportedSizes, widgets (no 1x1), actions, api block, and data-source consistency. Returns errors (blocking) and warnings (advisory). Mirrors the dashboard's own validator.
No pagination or result-limiting documented for tools that return large knowledge blocks (e.g., get_contracts, get_widgets_spec). If these return multi-KB responses, context window impact is not addressed.
Tool composition is strong (scaffold → validate → preview → package), but no explicit guidance in descriptions on when to skip steps (e.g., can you call create_plugin_zip without preview_widget?). Agents may over-call.