{"_id":"@deitum/camunda-mcp","_rev":"2-bec0b04300bc6b6b7bf8ca96d846688f","name":"@deitum/camunda-mcp","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@deitum/camunda-mcp","version":"0.2.0","keywords":["mcp","model-context-protocol","camunda","camunda7","bpmn","dmn","workflow","llm","ai"],"author":{"name":"Zvyagin Danila"},"license":"MIT","_id":"@deitum/camunda-mcp@0.2.0","maintainers":[{"name":"zvyagin","email":"zviagin.danila@gmail.com"}],"homepage":"https://github.com/deitum/camunda-mcp#readme","bugs":{"url":"https://github.com/deitum/camunda-mcp/issues"},"bin":{"camunda-mcp":"dist/cli.js"},"dist":{"shasum":"24ff45526f1c822bf83a7b5b2b1ca37cc291923e","tarball":"https://registry.npmjs.org/@deitum/camunda-mcp/-/camunda-mcp-0.2.0.tgz","fileCount":56,"integrity":"sha512-LvSYZ06932TzVKtaLikW7xTgzddNxiKdW1s2AzesNnTVhBbyVqOlYaJ4HDTZGIAG4+m3f6V+SSDNrUqb6XZfKQ==","signatures":[{"sig":"MEQCIB4sh3uU/lfQy2y1AY+PYr6FqsnTvw4cF98BY54GH/BpAiBJ9NB2rXO10ZR4RENsSNidudoGaRPZ3kKlytF7sHrILw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@deitum%2fcamunda-mcp@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":156170},"main":"./dist/index.js","type":"commonjs","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"2f4f7c0b48d101e44df91dd9dcd0b09f4c6adbc1","scripts":{"lint":"eslint .","test":"vitest run","build":"npm run clean && tsc -p tsconfig.build.json","clean":"rimraf dist coverage","format":"prettier --write .","verify":"npm run lint && npm run format:check && npm run typecheck && npm run test && npm run build && npm run check:package","prepack":"npm run build","release":"changeset publish","lint:fix":"eslint . --fix","changeset":"changeset","inspector":"npm run build && npx @modelcontextprotocol/inspector node dist/cli.js","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check .","check:package":"publint --strict && attw --pack . --entrypoints .","test:coverage":"vitest run --coverage","changeset:version":"changeset version && node scripts/sync-version.mjs && npm install --package-lock-only"},"_npmUser":{"name":"zvyagin","email":"zviagin.danila@gmail.com"},"repository":{"url":"git+https://github.com/deitum/camunda-mcp.git","type":"git"},"_npmVersion":"10.9.8","description":"MCP server for Camunda 7 — BPMN/DMN definitions, process instances, incidents, user tasks, history and DMN evaluation over the engine REST API.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^4.4.3","@modelcontextprotocol/sdk":"^1.30.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"packageManager":"npm@10.9.8","devDependencies":{"eslint":"^10.8.1","rimraf":"^6.1.3","vitest":"^4.1.10","globals":"^17.9.0","publint":"^0.3.23","prettier":"^3.9.6","@eslint/js":"^10.0.1","typescript":"^5.9.3","@types/node":"^20.19.43","@changesets/cli":"^2.31.1","typescript-eslint":"^8.66.0","@vitest/coverage-v8":"^4.1.10","@arethetypeswrong/cli":"^0.18.5","@vitest/eslint-plugin":"^1.6.27","eslint-config-prettier":"^10.1.8","eslint-plugin-import-x":"^4.17.1","eslint-import-resolver-typescript":"^4.4.5"},"_npmOperationalInternal":{"tmp":"tmp/camunda-mcp_0.2.0_1786401759621_0.11401966546906395","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@deitum/camunda-mcp","version":"0.3.0","description":"MCP server for Camunda 7 — BPMN/DMN definitions, process instances, incidents, user tasks, history and DMN evaluation over the engine REST API.","type":"commonjs","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"bin":{"camunda-mcp":"dist/cli.js"},"author":{"name":"Zvyagin Danila"},"license":"MIT","keywords":["mcp","model-context-protocol","camunda","camunda7","bpmn","dmn","workflow","llm","ai"],"homepage":"https://github.com/deitum/camunda-mcp#readme","bugs":{"url":"https://github.com/deitum/camunda-mcp/issues"},"repository":{"type":"git","url":"git+https://github.com/deitum/camunda-mcp.git"},"publishConfig":{"access":"public","provenance":true},"engines":{"node":">=20"},"packageManager":"npm@10.9.8","scripts":{"clean":"rimraf dist coverage","build":"npm run clean && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","lint":"eslint .","lint:fix":"eslint . --fix","format":"prettier --write .","format:check":"prettier --check .","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","check:package":"publint --strict && attw --pack . --entrypoints .","verify":"npm run lint && npm run format:check && npm run typecheck && npm run test && npm run build && npm run check:package","inspector":"npm run build && npx @modelcontextprotocol/inspector node dist/cli.js","prepack":"npm run build","changeset":"changeset","changeset:version":"changeset version && node scripts/sync-version.mjs && npm install --package-lock-only","release":"changeset publish"},"dependencies":{"@modelcontextprotocol/sdk":"^1.30.0","zod":"^4.4.3"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.5","@changesets/cli":"^2.31.1","@eslint/js":"^10.0.1","@types/node":"^20.19.43","@vitest/coverage-v8":"^4.1.10","@vitest/eslint-plugin":"^1.6.27","eslint":"^10.8.1","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.5","eslint-plugin-import-x":"^4.17.1","globals":"^17.9.0","prettier":"^3.9.6","publint":"^0.3.23","rimraf":"^6.1.3","typescript":"^5.9.3","typescript-eslint":"^8.66.0","vitest":"^4.1.10"},"_id":"@deitum/camunda-mcp@0.3.0","gitHead":"0d9b89f60c12561b5d1e40b0261f715e6b0b1c2f","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-s+DlSsOlFzQwafmiJksUuN/gHXGfCFVT9aRWAu+CkFonYL1oxm8u1HKGHsUxxE2SHOTkzklJrClCoLQmmOVa6Q==","shasum":"fa34bd449030256714eb37c3664aa60af4b17f71","tarball":"https://registry.npmjs.org/@deitum/camunda-mcp/-/camunda-mcp-0.3.0.tgz","fileCount":60,"unpackedSize":161615,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@deitum%2fcamunda-mcp@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDqOcTm+o/bWCnpj4lCAkdiqasAqbKKMxMPXFNv2g8fwQIgTpYH4OZneMLpT9G7iBNYNEPldRi4C4hvso69rwJERlg="}]},"_npmUser":{"name":"zvyagin","email":"zviagin.danila@gmail.com"},"directories":{},"maintainers":[{"name":"zvyagin","email":"zviagin.danila@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/camunda-mcp_0.3.0_1786966925865_0.25191798920413055"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T22:42:39.439Z","modified":"2026-08-17T11:42:06.465Z","0.2.0":"2026-08-10T22:42:39.828Z","0.3.0":"2026-08-17T11:42:06.018Z"},"bugs":{"url":"https://github.com/deitum/camunda-mcp/issues"},"author":{"name":"Zvyagin Danila"},"license":"MIT","homepage":"https://github.com/deitum/camunda-mcp#readme","keywords":["mcp","model-context-protocol","camunda","camunda7","bpmn","dmn","workflow","llm","ai"],"repository":{"type":"git","url":"git+https://github.com/deitum/camunda-mcp.git"},"description":"MCP server for Camunda 7 — BPMN/DMN definitions, process instances, incidents, user tasks, history and DMN evaluation over the engine REST API.","maintainers":[{"name":"zvyagin","email":"zviagin.danila@gmail.com"}],"readme":"# @deitum/camunda-mcp\n\nAn [MCP](https://modelcontextprotocol.io) server for **Camunda 7**: BPMN and DMN definitions,\nrunning instances, variables, user tasks, incidents, history, DMN evaluation — and, behind a flag,\nthe operations that change the engine.\n\nIt talks to the engine's REST API, so it works with a standalone distribution, a Spring Boot\napplication with `camunda-bpm-spring-boot-starter-rest`, and an engine published behind a reverse\nproxy alike. Authentication covers the four schemes those deployments actually use: none, HTTP\nBasic, a ready-made token, and an OAuth2 / OIDC token endpoint — with the token sent either as\n`Authorization: Bearer` or in a cookie.\n\n```bash\nnpx @deitum/camunda-mcp\n```\n\nIt speaks MCP over stdio and is configured entirely through environment variables.\n\n## Setting it up in a client\n\n**Claude Desktop** (`claude_desktop_config.json`), **Cursor**, **Windsurf** and anything else that\nreads the same shape:\n\n```json\n{\n  \"mcpServers\": {\n    \"camunda\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@deitum/camunda-mcp\"],\n      \"env\": {\n        \"CAMUNDA_BASE_URL\": \"http://localhost:8080/engine-rest\",\n        \"CAMUNDA_USERNAME\": \"demo\",\n        \"CAMUNDA_PASSWORD\": \"demo\"\n      }\n    }\n  }\n}\n```\n\n**Claude Code:**\n\n```bash\nclaude mcp add camunda \\\n  --env CAMUNDA_BASE_URL=http://localhost:8080/engine-rest \\\n  --env CAMUNDA_USERNAME=demo \\\n  --env CAMUNDA_PASSWORD=demo \\\n  -- npx -y @deitum/camunda-mcp\n```\n\n**VS Code** (`.mcp.json` / `.vscode/mcp.json`), where the password is prompted for rather than\nwritten down:\n\n```json\n{\n  \"inputs\": [\n    {\n      \"id\": \"camunda-password\",\n      \"type\": \"promptString\",\n      \"description\": \"Camunda password\",\n      \"password\": true\n    }\n  ],\n  \"servers\": {\n    \"camunda\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@deitum/camunda-mcp\"],\n      \"env\": {\n        \"CAMUNDA_BASE_URL\": \"http://localhost:8080/engine-rest\",\n        \"CAMUNDA_USERNAME\": \"demo\",\n        \"CAMUNDA_PASSWORD\": \"${input:camunda-password}\"\n      }\n    }\n  }\n}\n```\n\nA variable left as a literal `${input:NAME}` counts as unset, so a placeholder that was never\nfilled in reads as a missing value rather than being sent to the engine as a username.\n\n## Configuration\n\n| Variable                 | Required | Meaning                                                                    |\n| ------------------------ | -------- | -------------------------------------------------------------------------- |\n| `CAMUNDA_BASE_URL`       | yes      | Engine REST root ([which one?](#which-base-url)).                          |\n| `CAMUNDA_AUTH`           | –        | `none` \\| `basic` \\| `bearer` \\| `oauth`. Inferred when omitted.           |\n| `CAMUNDA_USERNAME`       | –        | User, for Basic auth or the OAuth password grant.                          |\n| `CAMUNDA_PASSWORD`       | –        | Its password.                                                              |\n| `CAMUNDA_TOKEN`          | –        | A ready-made token to send as-is (`bearer`).                               |\n| `CAMUNDA_TOKEN_URL`      | –        | OAuth2 / OIDC token endpoint (`oauth`).                                    |\n| `CAMUNDA_CLIENT_ID`      | –        | OAuth client.                                                              |\n| `CAMUNDA_CLIENT_SECRET`  | –        | Only for a confidential client.                                            |\n| `CAMUNDA_GRANT_TYPE`     | –        | `password` \\| `client_credentials`. Inferred from whether a user is given. |\n| `CAMUNDA_SCOPE`          | –        | Scope to request, if the provider needs one.                               |\n| `CAMUNDA_AUTH_TRANSPORT` | –        | `header` (default) \\| `cookie` — how the token reaches the engine.         |\n| `CAMUNDA_COOKIE_NAME`    | –        | Cookie to put it in when the transport is `cookie` (default `JWT`).        |\n| `CAMUNDA_ALLOW_WRITE`    | –        | `true` registers the tools that change the engine. Default off.            |\n| `CAMUNDA_SSL_VERIFY`     | –        | `false` stops verifying TLS certificates ([why](#tls)). Default on.        |\n| `CAMUNDA_MAX_RESULTS`    | –        | Default page size (default 20, hard cap 100).                              |\n| `CAMUNDA_TIMEOUT_MS`     | –        | Per-request budget (default 30000).                                        |\n\nThe two flags read `true`/`1`/`yes` and `false`/`0`/`no`; anything else leaves the default in\nplace, so a typo can only fail closed — writes off, certificates verified.\n\n## Authentication\n\nSet only the variables your engine needs; the mode follows from them, and `CAMUNDA_AUTH` is there\nfor the rare case where the guess is wrong.\n\n**None** — a local distribution with the auth filter switched off:\n\n```bash\nCAMUNDA_BASE_URL=http://localhost:8080/engine-rest\n```\n\n**HTTP Basic** — what Camunda's own `ProcessEngineAuthenticationFilter` speaks, and what\n`camunda-bpm-platform:run` ships with:\n\n```bash\nCAMUNDA_USERNAME=demo\nCAMUNDA_PASSWORD=demo\n```\n\n**A ready-made token** — one you already have from somewhere else:\n\n```bash\nCAMUNDA_TOKEN=eyJhbGciOi…\n```\n\n**OAuth2 / OIDC** — this server fetches tokens itself and renews them as they expire, sharing one\ngrant across concurrent tool calls and using the refresh token when the provider issues one:\n\n```bash\n# password grant\nCAMUNDA_TOKEN_URL=https://idp.example/realms/demo/protocol/openid-connect/token\nCAMUNDA_CLIENT_ID=camunda-client\nCAMUNDA_CLIENT_SECRET=…        # confidential clients only\nCAMUNDA_USERNAME=user\nCAMUNDA_PASSWORD=…\n\n# client-credentials grant — drop the user, that is the whole difference\nCAMUNDA_TOKEN_URL=https://idp.example/realms/demo/protocol/openid-connect/token\nCAMUNDA_CLIENT_ID=camunda-service\nCAMUNDA_CLIENT_SECRET=…\n```\n\nCredentials are all-or-nothing per mode: a half-filled set fails at startup, naming what is\nmissing, rather than turning every tool call into the engine's login page.\n\n### Bearer header or cookie?\n\nBy default a token travels as `Authorization: Bearer <token>`, which is what a Camunda engine\nexpects. Some deployments publish the engine behind a proxy or an OIDC filter that reads the token\nfrom a **cookie** and ignores the `Authorization` header entirely — for those:\n\n```bash\nCAMUNDA_AUTH_TRANSPORT=cookie\nCAMUNDA_COOKIE_NAME=JWT        # the default; change it if the filter uses another name\n```\n\nWhen the transport is `cookie` no `Authorization` header is sent at all. The symptom of getting\nthis wrong is a `302` to the identity provider while the same token works in the other position —\nthe error message says exactly that, and which variable to flip.\n\n### Which base URL?\n\n- standalone distribution or Spring Boot starter → `https://host/engine-rest`\n- deployment where only the webapp is exposed → `https://host/camunda/api/engine/engine/default`\n\nBoth serve the same API. Getting it wrong is the common failure and does not look like one — the\nfront-end that owns the wrong path tends to answer `200 text/html` — so the server checks for that\nand says which URLs to try.\n\n### TLS\n\nAn internally hosted engine is often signed by a private root that Node does not ship, so the first\ncall fails with `SELF_SIGNED_CERT_IN_CHAIN` while `curl` against the same URL works (it uses the\nsystem store). The error message says as much rather than repeating `fetch failed`.\n\nTwo ways out, in order of preference:\n\n```bash\nNODE_EXTRA_CA_CERTS=/path/to/internal-root.pem   # keeps verification, just teaches Node the root\nCAMUNDA_SSL_VERIFY=false                         # verifies nothing at all\n```\n\n`CAMUNDA_SSL_VERIFY=false` sets `NODE_TLS_REJECT_UNAUTHORIZED=0`, which is process-wide: Node's\n`fetch` takes TLS settings from the process, not per connection, so it covers the token endpoint\ntoo and there is no way to scope it to the engine alone. It leaves the connection open to\ninterception — use it against a development engine, and add the root certificate for anything else.\nThe startup banner on stderr says `TLS verification OFF` while it is in effect.\n\n## Tools\n\nRead-only, always registered:\n\n| Tool                                     | What it answers                                         |\n| ---------------------------------------- | ------------------------------------------------------- |\n| `camunda_list_decision_definitions`      | deployed DMN decisions (Cockpit's «Decisions»)          |\n| `camunda_get_decision_dmn`               | the DMN XML — the decision table itself                 |\n| `camunda_evaluate_decision`              | runs a decision against inputs, returns the output rows |\n| `camunda_list_decision_instances`        | evaluation history with inputs/outputs                  |\n| `camunda_list_process_definitions`       | deployed BPMN processes                                 |\n| `camunda_get_process_bpmn`               | the BPMN XML (source of activity ids)                   |\n| `camunda_list_process_instances`         | running instances, by key or business key               |\n| `camunda_get_activity_instances`         | where an instance is sitting right now                  |\n| `camunda_list_variables`                 | an instance's variables, unwrapped                      |\n| `camunda_list_tasks`                     | open user tasks                                         |\n| `camunda_list_incidents`                 | open incidents                                          |\n| `camunda_get_job_stacktrace`             | the exception behind a failed job                       |\n| `camunda_list_history_process_instances` | finished instances                                      |\n| `camunda_list_history_activities`        | one instance's audit trail                              |\n| `camunda_list_deployments`               | deployments, newest first                               |\n| `camunda_get_deployment_resource`        | a deployment's files, or one file's content             |\n| `camunda_get`                            | escape hatch: any engine `GET` by path                  |\n\nRegistered only with `CAMUNDA_ALLOW_WRITE=true`: `camunda_start_process_instance`,\n`camunda_complete_task`, `camunda_modify_process_instance`, `camunda_set_variables`,\n`camunda_send_message`, `camunda_set_job_retries`, `camunda_resolve_incident`,\n`camunda_delete_process_instance`.\n\nThe write half is _not registered_ rather than merely discouraged: a model cannot be told \"do not\ntouch\" reliably, but it cannot call a tool it was never shown.\n\n`camunda_evaluate_decision` is deliberately in the read half: it changes no engine state (only a\nhistory entry) and it is much of the reason to point this at an engine's decision tables.\n\nVariables are passed as plain JSON (`{\"amount\": 100}`) and typed automatically; pass the engine's\nown envelope (`{\"amount\": {\"value\": \"100\", \"type\": \"String\"}}`) when you need an exact type.\n\nResults are trimmed on the way back: list tools project each row down to the fields worth reading,\n`maxResults` is capped at 100, XML at 40 000 characters and any single result at 60 000 — an engine\npage of a few thousand rows would otherwise land in the model's context whole.\n\n## Troubleshooting\n\n| Symptom                                 | What it means                                                                                    |\n| --------------------------------------- | ------------------------------------------------------------------------------------------------ |\n| `302` to the identity provider          | The token was not accepted in the position it was sent — try the other `CAMUNDA_AUTH_TRANSPORT`. |\n| `returned HTML, not engine JSON`        | `CAMUNDA_BASE_URL` points at a front-end, not the engine REST root.                              |\n| `SELF_SIGNED_CERT_IN_CHAIN`             | Node does not trust the chain; see [TLS](#tls).                                                  |\n| `Incomplete <mode> credentials`         | A half-filled set — the message names the missing variables.                                     |\n| `Engine rejected the credentials (401)` | The engine understood the credentials and refused them.                                          |\n\nChecking a deployment by hand, which separates a bad URL from a bad token:\n\n```bash\ncurl -s -u demo:demo \"http://localhost:8080/engine-rest/decision-definition?maxResults=5\"\n```\n\nA JSON array means the base URL and the credentials are both right. HTML means the base URL is\nwrong. A `302` to an identity provider means the credentials were not accepted in that position.\n\n## Using it as a library\n\nThe stdio binary is the point, but the server is exported too — for a custom transport or a test\nharness:\n\n```ts\nimport { createCamundaServer, loadConfig } from '@deitum/camunda-mcp';\n\nconst server = createCamundaServer(loadConfig(process.env));\nawait server.connect(myTransport);\n```\n\n## Development\n\n```bash\nnpm install\nnpm run verify        # lint, format, types, tests, build, packaging\nnpm test              # vitest, no network\nnpm run inspector     # build, then drive it with the MCP inspector\n```\n\nAgainst a throwaway engine:\n\n```bash\ndocker run --rm -p 8080:8080 camunda/camunda-bpm-platform:run-latest\nCAMUNDA_BASE_URL=http://localhost:8080/engine-rest \\\n  CAMUNDA_USERNAME=demo CAMUNDA_PASSWORD=demo \\\n  npx @modelcontextprotocol/inspector node dist/cli.js\n```\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## Licence\n\n[MIT](./LICENSE).\n","readmeFilename":"README.md"}