Skip to content

Architecture

The platform is a single Node.js MCP server that exposes Camunda 7 / CIB Seven operations and Prometheus-backed analytics to any MCP host (Claude, ChatGPT, …). A Kotlin plugin in the engine emits process metrics via Micrometer, pushed over OTLP; the OTEL Collector exports them to Prometheus so the analytics module can query them.

At a glance

Modules

ModuleRole
MCP Server (apps/mcp-server-camunda7/)Hosts the HTTP transport on port 8400, loads modules from MCP_ACTIVE_MODULES, and serves the Vite-built React widget bundle (see widgets).
camunda7 (packages/connectors/camunda/camunda7-connector/)Wraps the Camunda 7 / CIB Seven REST API via an OpenAPI-generated client. Exposes process, task, incident, deployment, and history tools plus widgets.
analytics (packages/connectors/analytics/analytics-connector/)Queries Prometheus via PromQL for performance, failure, bottleneck, version/cluster comparison, and the cross-engine landscape. Tools + widgets.
engine-plugins (engine-plugins/)Kotlin Micrometer plugins for CIB Seven: a process-metrics emitter. Independent build (Java 21, Gradle). No engine-side database.
widgets (apps/mcp-server-camunda7/dist/mcp-app.js + .css)One Vite-built ES module + stylesheet containing React, Tailwind, and every widget. mcp-use serves it behind one ui://views/<tool>.html resource per widget tool; the host renders the bound view when a tool returns { widget, data }.

Composition rules

A small set of layering rules keeps modules independently usable and a future second engine dialect cheap:

  • App = one product per engine dialect. apps/mcp-server-camunda7 is the thin composition root of the Camunda-7-dialect product (camunda7 + analytics). Engine vendors of that dialect (CIB Seven, Operaton, Camunda 7) are per-engine runtime configuration (flavor on the engine entry, resolved to an EngineProvider carrying only the real differences: cockpit routes, branding, client hook) — never separate apps. A different dialect (e.g. Flowable, with its own REST API) would be its own module, client, and app.
  • Modules are peers. mcp-* packages never import each other. Cross-module capabilities are injected by the app — e.g. the camunda7 module's BPMN-XML lookup feeding the analytics heatmap (SharedResources.fetchBpmnXml).
  • Modules are self-contained. Each exports a module definition — config schema, env mapping, known env vars, boot warnings, plugin factory (packages/*/src/module.ts). The app only selects modules (MCP_ACTIVE_MODULES) and wires shared resources against its own port (apps/mcp-server-camunda7/src/module-contract.ts). The module packages are published to npm, so external composition roots can mount them next to their own modules — templates/composed-server/ is the reference.
  • Apps own no domain UI. Widgets and their catalogues live in packages: widget-shell carries the generic primitives plus the shell:* widgets; each module carries its own. Cross-module UI has three sanctioned tiers — generic shell:* widgets fed via props.dataKey, tool-name string references with graceful degradation, and hard-composed views in a dedicated package (created with the first real view).
  • Extract on the second consumer, never speculatively. A composed-views package appears with the first cross-module view, a shared domain-widget package with a second dialect, a host-kit with a second app.

User settings

Preferences live in one profile record per user, shared by every module and persisted in Postgres (DATABASE_URL), on disk (MCP_PROFILE_DIR), or in memory — in that order of precedence. The record is keyed by the authenticated user when the server runs with MCP_OAUTH, otherwise by the MCP session id.

PartOwnerContents
Core record + storewidget-shellLanguage, theme, record metadata, the slice transport, the stores
modules.<module> slicethat moduleWhatever only it understands — e.g. camunda7's engine picks

Each module owns its slice end to end: its own schema, its own save tool, and its own section on the settings page. Nothing central knows what a slice contains — the record only transports it, and a save merges per module key, so one module can never overwrite another's settings. Reads are fail-soft throughout: an unreadable slice or an unreachable store yields defaults rather than an error, so a profile-store hiccup can't break a call that only needs the engine or Prometheus.

The settings page composes one section widget per module and assembles itself from the widgets the server actually bundles — every widget id ending in :settings becomes a row. A module that isn't mounted simply has no section instead of producing a broken tab, and a custom module in a composed server contributes its section by that convention alone.

External systems

SystemPurposeDefault endpoint
Camunda 7 / CIB SevenThe BPM engine itself — process definitions, instances, tasks, incidents.http://localhost:8410/engine-rest
OpenTelemetry collectorReceives OTLP from the engine; exports metrics to Prometheus.:8431 (OTLP HTTP)
PrometheusTime-series store for the process metrics; the analytics module's data source.http://localhost:8460
GrafanaProvisioned process-analytics dashboards over Prometheus.http://localhost:8470

Data flow

  1. The MCP host calls a tool on the server (e.g. analytics_element_bottleneck).
  2. The server delegates to the matching module's plugin.
  3. The plugin calls the relevant system (REST for the engine, PromQL for Prometheus) and returns structured content.
  4. Widget tools also return a widget key — the host renders the corresponding React component from the shared bundle and feeds it the data.

Process metrics originate in the engine: the Kotlin plugin maps history events to Micrometer counters/histograms (100 % coverage, model-bounded labels), the Collector receives them over OTLP, and Prometheus stores them. Per-instance drill-down (search) is served by the engine REST history API, not the metrics.

Repository layout

PathDescription
apps/mcp-server-camunda7/The MCP server entry point and the widget bundle.
packages/Reusable libraries — clients, MCP plugins, widget-shell.
engine-plugins/Kotlin Micrometer plugins (process metrics).
playground/Demo env: showcases, Compose stack, Fly.io deployment.

For deeper detail, the root README.md keeps the full module table and tool list.