Metadata-Version: 2.4
Name: elsa-mcp
Version: 0.1.dev9
Summary: MCP server for authoring Elsa Workflows 3 definitions against a live Elsa engine.
Project-URL: Repository, https://github.com/neoblue-tech/elsa-mcp
Project-URL: Issues, https://github.com/neoblue-tech/elsa-mcp/issues
Author-email: Cristina Mudura <info@neobluetech-labs.io>
License: MIT
Keywords: claude,elsa,mcp,model-context-protocol,workflows
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: anyio>=4.4
Requires-Dist: cachetools>=5.4
Requires-Dist: httpx>=0.27
Requires-Dist: mcp[cli]>=1.27.1
Requires-Dist: pydantic-settings>=2.4
Requires-Dist: pydantic>=2.7
Requires-Dist: structlog>=24.4
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# 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` / `full` modes)
- Short-TTL descriptor caching with stale-on-error fallback
- Structured, actionable validation errors

## Install

```bash
# Recommended: uv
uv sync
# Or with pip
pip install -e ".[dev]"
```

## 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, but `publish` is forced to `false`. 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.

## Run locally (stdio, Claude Desktop)

Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "elsa-dev": {
      "command": "/Users/you/.local/bin/uv",
      "args": ["--directory", "/absolute/path/to/elsa-mcp", "run", "elsa-mcp"],
      "env": {
        "ELSA_BASE_URL": "https://localhost:5001",
        "ELSA_API_KEY": "dev-key-here",
        "ELSA_MODE": "full",
        "ELSA_VERIFY_TLS": "false"
      }
    }
  }
}
```

> Use **absolute paths** for the command — Claude Desktop does not inherit your shell `PATH`.

## Run hosted (Streamable HTTP)

```bash
ELSA_BASE_URL=https://elsa.example.com \
ELSA_API_KEY=... \
ELSA_MODE=draft \
uv run elsa-mcp --http --host 0.0.0.0 --port 8000
```

Put TLS termination + bearer-token validation in a reverse proxy (Caddy / Traefik) in front.

## Inspect with the MCP Inspector

```bash
npx @modelcontextprotocol/inspector \
  uv --directory $(pwd) run elsa-mcp
```

Opens a browser UI on `http://localhost:6274` where you can manually exercise tools and resources.

## Spin up a test Elsa server

```bash
docker run --rm -p 13000:8080 \
  -e ASPNETCORE_ENVIRONMENT=Development \
  -e HTTP_PORTS=8080 \
  elsaworkflows/elsa-server-and-studio-v3:latest
```

Then point `ELSA_BASE_URL=http://localhost:13000` and run `elsa-mcp`. Default credentials are
`admin / password`.

## Testing

```bash
uv run pytest
```

Unit tests use `respx` to mock the Elsa REST API.

## License

MIT
