Skip to content
Skills Library
AI & agents · Tool integration

setup-server

/setup-server

Set up, configure, run, brand, and deploy this composed MCP server. Use whenever connecting a Camunda 7 / CIB Seven engine or Prometheus, selecting modules or toolsets (`MCP_ACTIVE_MODULES`), configuring persistence, renaming the `@acme` scope, building the Docker image, running behind an MCP gateway, or troubleshooting boot warnings, empty analytics, or inspector issues.

Repository
pulse ↗
Licence
MIT
Last repository change
27.10.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
10
Deprecation

No signals detected. Repository changed on 27.10.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What it does and when to use it

Set up, configure, run, brand, and deploy this composed MCP server. Use whenever connecting a Camunda 7 / CIB Seven engine or Prometheus, selecting modules or toolsets (`MCP_ACTIVE_MODULES`), configuring persistence, renaming the `@acme` scope, building the Docker image, running behind an MCP gateway, or troubleshooting boot warnings, empty analytics, or inspector issues.

Original author description

Set up, configure, run, brand, and deploy this composed MCP server. Use whenever connecting a Camunda 7 / CIB Seven engine or Prometheus, selecting modules or toolsets (`MCP_ACTIVE_MODULES`), configuring persistence, renaming the `@acme` scope, building the Docker image, running behind an MCP gateway, or troubleshooting boot warnings, empty analytics, or inspector issues.

How it works

  1. Step 1: install and first run
  2. Step 2: connect the engine and Prometheus
  3. Step 3: select modules and toolsets
  4. Step 4: persistence
  5. Step 5: make it yours
  6. Step 6: Docker and production
  7. Step 7: connect an assistant
  8. Step 8: verify
  9. Troubleshooting
Original SKILL.md headings · 274 lines, 1,919 words
SKILL.md preview
---
name: setup-server
description: Set up, configure, run, brand, and deploy this composed MCP server. Use whenever connecting a Camunda 7 / CIB Seven engine or Prometheus, selecting modules or toolsets (`MCP_ACTIVE_MODULES`), configuring persistence, renaming the `@acme` scope, building the Docker image, running behind an MCP gateway, or troubleshooting boot warnings, empty analytics, or inspector issues.
allowed-tools: Read, Edit, Write, Glob, Grep, Bash
---

# setup-server: from clone to running (and deployed) server

Configuration ground rules first:

- **`.env` is a `pnpm dev` convenience only** (loaded via dotenv-cli).
  `pnpm start` and the Docker image take their config from the environment.
- **`.env.example` documents every variable this server reads**, with defaults:
  it is the configuration reference, kept honest by
  `server/test/env-example.test.ts`.
- The server **warns at boot about unknown env vars** under any watched prefix
  (`MCP_`, `CAMUNDA_`, `PROMETHEUS_`, plus each custom module's prefix); a
  boot warning means a typo or a var this build doesn't read, never noise.

## Step 1: install and first run

```bash
pnpm install    # needs Node >= 22.22.2 (enforced at install time)
cp .env.example .env
pnpm dev        # MCP endpoint on :8400/mcp, inspector on :8400/mcp/inspector
```

Verify before configuring anything: open `http://localhost:8400/mcp/inspector` and
call `notes_show_notes`: the example module needs no external infrastructure,
so a rendered notes widget proves server, widget bundle, and inspector work.
Then read the boot log: every warning there is actionable (unknown env var,
missing Prometheus URL, engine auth problems), and one info line
(`[acme-mcp] Toolsets — camunda7:read-only (default without OAuth), …`) states
what each module may do, read-only until you widen it or set `MCP_OAUTH`
(Step 3).

## Step 2: connect the engine and Prometheus

Edit `.env` (every field is documented inline in `.env.example`):

- `CAMUNDA_BASE_URL`: the engine REST endpoint.
- `CAMUNDA_ENGINE_ID`: **must match the `ENGINE_ID` the engine stamps onto its
  metrics.** Analytics reads only the configured engine ids, so the mismatch
  is silent: every analytics tool returns nothing for that engine and its
  health reads `unknown`.
- `CAMUNDA_ENGINE_FLAVOR`: the engine's vendor, `camunda7` (default), `cibseven` or `operaton`. It
  picks the cockpit-link routes and the product name the views show, so a CIB seven engine (the
  playground's) sets `cibseven`.
- `CAMUNDA_AUTH_TYPE`: `none | basic | bearer | passthrough`; `basic` needs
  `CAMUNDA_USERNAME`/`CAMUNDA_PASSWORD`, `bearer` needs `CAMUNDA_TOKEN` (both
  enforced at boot); `passthrough` forwards each MCP caller's own bearer token.
- `CAMUNDA_COCKPIT_URL`: set explicitly whenever the engine URL is not
  reachable from the user's browser (container hostname), otherwise "open in
  cockpit" links point nowhere.
- Multiple engines: `CAMUNDA_ENGINES_JSON` (or `CAMUNDA_ENGINES_FILE`) with
  per-engine `id`, `baseUrl`, optional `environment`, `flavor` (`cibseven |
operaton | camunda7`, default `camunda7`) and `auth`; overrides the single-engine shorthand
  above. To group engines by environment, either set `environment` per entry
  or write the JSON as a map keyed by environment id
  (`{"<environment>": [engines…]}`); pickers and `camunda7_list_engines`
  then group the engines by environment. Engine ids stay
  globally unique across environments.
- `PROMETHEUS_URL`: unset defaults to `http://localhost:9090`, which does
  **not** match the playground stack (host port 8460); every analytics query
  then fails. The server warns at boot when unset. A protected Prometheus takes
  `PROMETHEUS_BEARER_TOKEN` or `PROMETHEUS_USERNAME`/`PROMETHEUS_PASSWORD`
  (plus `PROMETHEUS_HEADERS`, a JSON object, e.g. for a tenant id).
- Analytics reads only the server's configured engines, camunda7's engine ids
  (a shared Prometheus never exposes other teams' engines). Without camunda7,
  name them in `ANALYTICS_ENGINE_IDS` (comma-separated `engine_id`s); with
  neither, every analytics tool refuses.
- `CAMUNDA_REQUEST_TIMEOUT_MS` / `PROMETHEUS_TIMEOUT_MS`: per-request
  deadlines (default 30000 ms); a hung upstream then fails the tool call with
  a timeout error instead of holding it.

No engine at hand? The
[Pulse playground](https://github.com/Miragon/pulse/tree/main/playground)
is a ready-made Docker Compose stack (engine + Prometheus + Grafana) whose
defaults match this template's `.env.example`.

## Step 3: select modules and toolsets

`MCP_ACTIVE_MODULES` is a comma list; unset or `all` activates every module.
Each module runs ONE toolset per boot, named by a `module:toolset` suffix:

```bash
MCP_ACTIVE_MODULES=camunda7:operations,analytics:standard,notes
```

- camunda7 supports `read-only | operations | admin`; analytics
  `read-only | standard` (`standard` adds the settings save).
- **Fail-closed default.** Without `MCP_OAUTH` a module without a suffix runs
  `read-only`; with it, its standard toolset (camunda7 `operations`, analytics
  `standard`). An empty (`camunda7:`) or unknown suffix warns and falls back to
  `read-only`; `admin` (delete/modify, migrations, signals, the external-task
  worker protocol) is only ever reached by naming it. Check the boot log's
  `Toolsets —` line after every change.
- `camunda7_create_deployment` additionally needs `CAMUNDA_ALLOW_DEPLOYMENTS=true`
  next to `camunda7:admin`: deploying a BPMN/DMN runs code inside the engine
  JVM (JUEL expressions, scripts). Strict `true`/`false` (empty = unset); junk fails the boot.
- Widening is a security decision: without `MCP_OAUTH` the server listens on
  all interfaces with no auth, so write toolsets are open to anyone who
  reaches the port. Behind an authenticating gateway the server still sees no
  identity, which is exactly why the suffix must stay explicit there, and why
  settings cannot be saved there: identity reaches the server only through
  `MCP_OAUTH`.
- Unknown module names warn and are skipped; a suffix on a module without
  toolsets (e.g. `notes:read-only`) warns and is ignored; that module
  registers all its tools.
- All widgets stay in the one Vite bundle regardless; inactive modules just
  register no tools. Module selection is runtime-only; there is no per-module
  bundle.

### OAuth: sign-in and per-user settings

```bash
MCP_URL=https://mcp.example.com     # the token audience (RFC 8707) — required with OAuth
MCP_OAUTH={"provider":"keycloak","serverUrl":"https://kc.example.com","realm":"platform"}
# or: MCP_OAUTH={"provider":"auth0","domain":"tenant.eu.auth0.com"}
```

`server/src/app.ts` wires it through `oauthFromEnv`
(`@miragon/pulse-widget-shell/server`), the same helper the stock server uses.
`/mcp` then answers 401 without a valid bearer token, the default toolsets rise
to `operations`/`standard`, and every settings save (`shell_save_settings` for
the language, `camunda7_save_settings`, `analytics_save_settings`,
`camunda7_select_engine`, your own module's save tool) persists under the
signed-in user. Without `MCP_OAUTH` there is no caller
identity: settings render their defaults and every save refuses. A bad
`MCP_OAUTH` (invalid JSON, unknown provider or key, stray `MCP_USE_OAUTH_*`
vars) fails the boot.

## Step 4: persistence

Both stores default to **in-memory**: everything is lost on restart. For real
deployments point them at directories (mounted volumes in Docker):

```bash
MCP_PROFILE_DIR=./.data/profiles       # per-user settings (language, module slices) — filled under MCP_OAUTH
MCP_DASHBOARD_DIR=./.data/dashboards   # saved builder dashboards — only under MCP_OAUTH (builder is off without it)
```

Postgres stores are deliberately trimmed from this template; the stock server
(`apps/mcp-server-camunda7` in the
[Pulse repo](https://github.com/Miragon/pulse)) is the reference
(README, "Going further").

## Step 5: make it yours

Renaming the placeholder scope touches a fixed set of places. Do all of them,
then reinstall so the lockfile matches:

1. `@acme/composed-mcp-server` in `server/package.json` (the `Dockerfile`
   selects packages by path, no edit there)
2. `@acme/mcp-notes` in `modules/mcp-notes/package.json`, in
   `server/package.json`'s dependencies, and in every import
   (`server/src/setup.ts`, `server/src/ui/widget-registry.ts`,
   `server/test/widget-registry.test.ts`)
3. the `acme-mcp` labels in `server/src/app.ts` and `setup.ts`
4. `pnpm install` to refresh `pnpm-lock.yaml` (the Docker build uses
   `--frozen-lockfile`)

Branding: `server/src/ui/brand.css` imports the toolkit's Miragon theme (the
default) and has one override block for light and one for dark. Set ROLE
variables there only (`--primary`, `--primary-hover`, `--link`, `--focus`,
`--ring`, `--accent`/`--accent-foreground`, `--input`, `--<tone>`/`-soft`/
`-ink`, radii, shadows, `--font-sans`) in BOTH blocks (the host's dark mode
matches `:root` too). Miragon blue also sits in `--info`, `--chart-1/-3` and
`--sidebar-*`; set those too for a single brand. The neutrals (surfaces, the
text on them, `--border`) are the host's: a host that sends SEP-1865 style
variables writes them inline on `<html>`, so a value set in brand.css shows
only where the host sends none. Check your colours against a light and a
dark host surface. Never set the `--cd-*` tokens, never colour a widget with
palette classes. `server/test/brand.test.ts` measures the role and tone
pairs (text and each `-foreground` on its fill 4.5:1, edges, dots, icons and
the focus ring 3:1) in light and dark over the Miragon neutrals; charts, the
sidebar, radii, shadows and fonts it does not measure. The widgets follow the
host's theme; there is no theme switch in the app.

## Step 6: Docker and production

```bash
pnpm install                    # once, then COMMIT pnpm-lock.yaml
docker build -t my-mcp-server .
docker run -p 127.0.0.1:8400:8400 \
  -e CAMUNDA_BASE_URL=http://host.docker.internal:8410/engine-rest \
  -e CAMUNDA_ENGINE_FLAVOR=cibseven \
  -e MCP_PROFILE_DIR=/data/profiles -v mcp-data:/data \
  my-mcp-server
```

- Config comes from the environment; the image does not read `.env`.
- `PORT` sets the HTTP port (default 8400); `MCP_URL` is the public base URL
  when running behind a proxy or MCP gateway and, with
  `MCP_ALLOWED_HOSTS`/`MCP_ALLOWED_ORIGINS`, the only non-localhost
  `Host`/`Origin` the server accepts: anything else gets 403 (DNS-rebinding
  protection), with the message naming the variable to set. It is also the
  origin the views load Geist from (the server's own `/fonts/geist-<version>/`
  route, declared in every view's CSP `resourceDomains`): behind a gateway,
  route `/fonts/` to the server too, or the views show the host's font.
- Federation/aggregation across MCP servers belongs in an external gateway
  (e.g. agentgateway) IN FRONT of this server; this repo builds one
  self-contained server; don't add upstream/proxy mechanics to it.

## Step 7: connect an assistant

The server speaks streamable HTTP on `/mcp`; how a host gets there differs per
host.

**Claude Desktop** takes stdio servers ONLY: its `claude_desktop_config.json`
validates the `command`/`args` shape, and a `"url"` entry is dropped silently
(older builds crashed at startup instead). Bridge the HTTP endpoint with
`mcp-remote`, via Settings → Developer → Edit Config
(macOS `~/Library/Application Support/Claude/claude_desktop_config.json`,
Windows `%APPDATA%\Claude\claude_desktop_config.json`), then restart the app:

```json
{
  "mcpServers": {
    "my-mcp-server": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://127.0.0.1:8400/mcp", "--transport", "http-only"]
    }
  }
}
```

`127.0.0.1` over `localhost`: Node may resolve the name to IPv6 while the
server listens on IPv4. Connection problems show up in the host's MCP logs:
`~/Library/Logs/Claude/mcp*.log` (Windows: `%APPDATA%\Claude\logs`).

**Claude Code** speaks HTTP natively, no bridge:

```bash
claude mcp add --transport http my-mcp-server http://localhost:8400/mcp
```

**claude.ai / ChatGPT custom connectors** need a server reachable over the
public internet (an `https://…/mcp` URL), so a deployment, not localhost. For
a throwaway test of a local build, `--tunnel` exposes it publicly. Run it
through dotenv from the repo root: `mcp-use dev` only reads a `.env` next to
itself (`server/.env`), never this repo's root one, so a bare
`mcp-use dev --tunnel` in `server/` tunnels a server with no engine or
Prometheus configured:

```bash
pnpm exec dotenv -e .env -- pnpm --filter ./server exec mcp-use dev --tunnel --no-open
```

Under `mcp-use dev` the CLI checks `Host` itself and admits its tunnel host,
so the tunnel needs no `MCP_ALLOWED_HOSTS` (browser `Origin`s are still
checked). A built server (`pnpm start`, the image) behind a tunnel or proxy
needs `MCP_URL` set to the public URL, else every call gets 403.

## Step 8: verify

```bash
pnpm build && pnpm typecheck && pnpm test
```

Then a functional pass in the inspector: `camunda7_list_engines` (engines
configured), one cheap read such as `camunda7_list_process_definitions` (engine
reachable, auth works), one `camunda7_show_*` widget, one analytics tool (Prometheus
reachable, `engine_id` matches). A clean boot log (no unknown-var or
missing-URL warnings) is part of done.

## Troubleshooting

| Symptom                                   | Cause                                                                                                                                                                                                              |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Every in-widget query hangs on "Loading…" | `resolve.dedupe` in `server/vite.config.ts` was trimmed, or a second copy of React/toolkit/mcp-use got installed                                                                                                   |
| Widgets render unstyled                   | widget sources outside the Tailwind scan set (workspace modules are globbed; npm-installed ones need an `@source` in `server/src/ui/globals.css`)                                                                  |
| Analytics tools return empty results      | `CAMUNDA_ENGINE_ID` doesn't match the engine's metrics `ENGINE_ID`, or `PROMETHEUS_URL` points at the wrong port                                                                                                   |
| Cockpit links open the wrong web app      | the engine's vendor: without `CAMUNDA_ENGINE_FLAVOR` (or a `flavor` per engine entry) it counts as Camunda 7                                                                                                       |
| "Unknown environment variable" at boot    | typo, or a var this build doesn't read; `.env.example` is the authoritative list                                                                                                                                   |
| Widget UI changes don't show up           | the bundle is read once at boot; restart `pnpm dev` at the repo root (it rebuilds modules + bundle on start)                                                                                                       |
| A tool is missing                         | module not in `MCP_ACTIVE_MODULES`, or its toolset filtered it; with no suffix and no `MCP_OAUTH` it is `read-only` (see the boot log's `Toolsets —` line); deployments also need `CAMUNDA_ALLOW_DEPLOYMENTS=true` |
| Claude Desktop shows no tools at all      | a `"url"` entry in `claude_desktop_config.json` (stdio only, use the `mcp-remote` bridge from Step 7), or the app wasn't restarted                                                                                 |

Versions

RepositoryScoreLicence
This page · miragon/pulse100MIT
chapmanjw/minecraft-java-fabric-claude-plugin100MIT

Database snapshot: 13.11.2026 · package version 6b2aab2c9a33 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100pulse-cli
    Inspect and operate Camunda 7, Operaton and CIB seven process engines through their REST API with pulse-cli (deployments, process instances, user tasks, external tasks, incidents, jobs, history, variables, decisions), and drive process instances with its workflow commands…
  • 81mcp-setup
    Use when installing, configuring, debugging, or verifying an MCP server for a harness, or when a configured server's tools are missing or failing.
  • 100mcp-setup
    Configure MCP servers and integrations. Use for "setup MCP", "configure server", and "MCP integration".
  • 100wren-mcp-setup
    Set up Wren Engine MCP server via Docker and register it with an AI agent. Covers pulling the Docker image, running the container with docker run, mounting a workspace, configuring connection info via the Web UI (with Docker host hint), registering the MCP server in Claude Code…
  • 84github-setup
    Set up GitHub MCP server authentication. Use when user says "setup github", "configure github token", "github mcp setup", or needs help configuring their GitHub Personal Access Token for the GitHub MCP server.
  • 100add-bpm-feature
    Step-by-step house pattern for adding a new BPM operations tool, widget tool, or widget to the camunda7 module (`packages/connectors/camunda/camunda7-connector` + `packages/connectors/camunda/camunda7-client`). Use whenever adding or changing Camunda 7 / CIB Seven tools ("add a…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.