MCP server for authoring Elsa Workflows 3 definitions against a live Elsa engine.
Project description
elsa-mcp
An MCP (Model Context Protocol) server in Python that lets an AI client author Elsa Workflows 3
definitions against a live Elsa engine. The catalog of activities is fetched from the engine's
own /elsa/api/descriptors/activities endpoint — the same one Elsa Studio uses — so the MCP always
reflects whatever modules, custom activities, and dynamic providers are actually loaded on the
target server.
Architecture
[AI client] ──MCP──▶ [elsa-mcp (this project)] ──HTTPS──▶ [Elsa server]
(stateless adapter) (the engine, untouched)
elsa-mcp is a separate process from Elsa. It depends on Elsa's public REST API and adds:
- LLM-friendly tool surfaces (search → fetch → validate → publish)
- A curated authoring guide as an MCP resource
- Capability gating (
readonly/draft/fullmodes) - Short-TTL descriptor caching with stale-on-error fallback
- Structured, actionable validation errors
Install from PyPI
# Recommended — installs the elsa-mcp command into ~/.local/bin
uv tool install elsa-mcp
# Include preview/dev releases
uv tool install --prerelease=allow elsa-mcp
# Alternative: pipx
pipx install elsa-mcp
After install, verify:
which elsa-mcp # → /Users/<you>/.local/bin/elsa-mcp
elsa-mcp --help
To upgrade or uninstall later:
uv tool upgrade elsa-mcp
uv tool uninstall elsa-mcp
Configure
Set environment variables (the server reads them at startup):
| Variable | Required | Default | Description |
|---|---|---|---|
ELSA_BASE_URL |
yes | https://localhost:5001 |
Base URL of the Elsa server |
ELSA_API_KEY |
yes* | — | API key for Authorization: ApiKey <KEY> |
ELSA_BEARER_TOKEN |
yes* | — | Alternative: JWT for Authorization: Bearer <JWT> |
ELSA_MODE |
no | readonly |
One of readonly, draft, full |
ELSA_VERIFY_TLS |
no | true |
Set false to accept self-signed dev certs |
ELSA_CACHE_TTL |
no | 60 |
Descriptor cache TTL in seconds |
* one of ELSA_API_KEY / ELSA_BEARER_TOKEN is required.
Capability modes
readonly— only search/get/list/validate tools registered. Safe default for production.draft— adds create/update tools, butpublishis forced tofalse. Good for staging.full— adds publish + dispatch. Use only on dev environments.
Tools are registered conditionally at startup — in readonly mode the LLM literally cannot
see the write tools.
Wire up to Claude
Claude Code
claude mcp add elsa \
-e ELSA_BASE_URL=http://localhost:12000 \
-e ELSA_BEARER_TOKEN=<jwt> \
-e ELSA_MODE=draft \
-- "$(which elsa-mcp)"
Argument order matters: the server name comes before the -e flags, and -- separates them
from the command path. Without --, the variadic -e swallows the path and you'll get
error: missing required argument 'commandOrUrl'.
Add -s user to register globally across all projects, or -s project to write a shareable
.mcp.json in the current repo.
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"elsa": {
"command": "/Users/<you>/.local/bin/elsa-mcp",
"env": {
"ELSA_BASE_URL": "http://localhost:12000",
"ELSA_BEARER_TOKEN": "<jwt>",
"ELSA_MODE": "draft"
}
}
}
}
Use the output of which elsa-mcp for the command path — Claude Desktop does not inherit your
shell PATH, so absolute paths are required. Fully quit and relaunch the app after editing.
Run hosted (Streamable HTTP)
ELSA_BASE_URL=https://elsa.example.com \
ELSA_API_KEY=... \
ELSA_MODE=draft \
elsa-mcp --http --host 0.0.0.0 --port 8000
Put TLS termination + bearer-token validation in a reverse proxy (Caddy / Traefik) in front.
Spin up a test Elsa server
The repo ships a docker-compose.yml with the Elsa server + Studio:
docker compose up -d
# Elsa server → http://localhost:12000
# Elsa Studio → http://localhost:13000 (default login: admin / password)
Then point ELSA_BASE_URL=http://localhost:12000 when running elsa-mcp.
Inspect with the MCP Inspector
npx @modelcontextprotocol/inspector elsa-mcp
Opens a browser UI on http://localhost:6274 where you can manually exercise tools and resources.
Develop from source
git clone https://github.com/neoblue-tech/elsa-mcp.git
cd elsa-mcp
uv sync # installs deps + creates .venv
uv run elsa-mcp --help # run without installing globally
uv tool install --editable . # OR: install on PATH, live-reloading from source
Run tests:
uv run pytest
Unit tests use respx to mock the Elsa REST API.
Releasing
The project is published to PyPI by .github/workflows/publish.yml:
- Push to
main→ publishes a previewX.Y.Z.devNto PyPI (only installable withuv tool install --prerelease=allow elsa-mcp). - Tag
vMAJOR.MINOR.PATCH→ publishes the stable version + creates a GitHub Release.
Versions are derived from git via hatch-vcs; no manual version bumps required.
git tag v0.1.0
git push origin v0.1.0
# → publishes elsa-mcp==0.1.0
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file elsa_mcp-0.1.dev10.tar.gz.
File metadata
- Download URL: elsa_mcp-0.1.dev10.tar.gz
- Upload date:
- Size: 134.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2d792d557cb986607c8993edfb2c0513922e269181731178ca5616c39394cef
|
|
| MD5 |
0ad993df0acbe3e8927fae92649176f8
|
|
| BLAKE2b-256 |
ce3dd901caf3c936d4979cb30fd5bfe87f16e263eb99739941abc508a537b24b
|
Provenance
The following attestation bundles were made for elsa_mcp-0.1.dev10.tar.gz:
Publisher:
publish.yml on neoblue-tech/elsa-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
elsa_mcp-0.1.dev10.tar.gz -
Subject digest:
a2d792d557cb986607c8993edfb2c0513922e269181731178ca5616c39394cef - Sigstore transparency entry: 1566605432
- Sigstore integration time:
-
Permalink:
neoblue-tech/elsa-mcp@91ab672c50e3a3f3bb285b9a774faa2b8ad1099d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/neoblue-tech
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91ab672c50e3a3f3bb285b9a774faa2b8ad1099d -
Trigger Event:
push
-
Statement type:
File details
Details for the file elsa_mcp-0.1.dev10-py3-none-any.whl.
File metadata
- Download URL: elsa_mcp-0.1.dev10-py3-none-any.whl
- Upload date:
- Size: 50.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc96f01153de0da43c0d5add4b04b7bd59f07e9ea253e07405460753ae9e96f7
|
|
| MD5 |
8104f9bbb363546acdb4e12dbb7b06e0
|
|
| BLAKE2b-256 |
5febd76ec2c74c9f9fb207665ef5e727feeda4e85ac3d6ea4c5bb845666a4b48
|
Provenance
The following attestation bundles were made for elsa_mcp-0.1.dev10-py3-none-any.whl:
Publisher:
publish.yml on neoblue-tech/elsa-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
elsa_mcp-0.1.dev10-py3-none-any.whl -
Subject digest:
bc96f01153de0da43c0d5add4b04b7bd59f07e9ea253e07405460753ae9e96f7 - Sigstore transparency entry: 1566605442
- Sigstore integration time:
-
Permalink:
neoblue-tech/elsa-mcp@91ab672c50e3a3f3bb285b9a774faa2b8ad1099d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/neoblue-tech
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91ab672c50e3a3f3bb285b9a774faa2b8ad1099d -
Trigger Event:
push
-
Statement type: