Metadata-Version: 2.4
Name: workflows-mcp
Version: 9.14.0
Summary: MCP server for DAG-based workflow execution with YAML definitions and LLM collaboration
Project-URL: Homepage, https://github.com/qtsone/workflows-mcp
Project-URL: Repository, https://github.com/qtsone/workflows-mcp
Project-URL: Documentation, https://github.com/qtsone/workflows-mcp/blob/main/README.md
Project-URL: Issues, https://github.com/qtsone/workflows-mcp/issues
Project-URL: Changelog, https://github.com/qtsone/workflows-mcp/blob/main/CHANGELOG.md
Author-email: Iulian Bacalu <ibacalu@icloud.com>
License-Expression: AGPL-3.0-or-later
License-File: LICENSE
Keywords: automation,claude,dag,llm-collaboration,mcp,workflow
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.12
Requires-Dist: asyncpg>=0.31.0
Requires-Dist: cryptography>=41.0.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: jsonschema>=4.0
Requires-Dist: mcp[cli]>=1.26.0
Requires-Dist: openai>=1.68.0
Requires-Dist: pathspec>=0.12.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pyjwt[crypto]>=2.8.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: sqlite-vec>=0.1.6
Requires-Dist: tree-sitter-languages>=1.10.0
Requires-Dist: types-pyyaml>=6.0.12.20250915
Provides-Extra: benchmark
Requires-Dist: fastembed>=0.7.3; extra == 'benchmark'
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: mariadb
Requires-Dist: aiomysql>=0.2.0; extra == 'mariadb'
Provides-Extra: postgresql
Provides-Extra: sql-all
Requires-Dist: aiomysql>=0.2.0; extra == 'sql-all'
Description-Content-Type: text/markdown

# Workflows MCP

Run YAML workflows as MCP tools so agents can automate real tasks with one server.

## Why this project

`workflows-mcp` gives MCP clients a reusable automation layer:

- Define tasks once in YAML and run them from any MCP-compatible client.
- Orchestrate multi-step work with dependency-aware execution.
- Support interactive runs (`Prompt` blocks) with pause/resume.
- Keep secrets server-side via `WORKFLOW_SECRET_*` with redacted outputs.
- Run synchronous or async jobs with queue visibility and cancellation.

## Quickstart (5 minutes)

### 1) Install

Requires Python 3.12+.

```bash
uv pip install workflows-mcp
```

or:

```bash
pip install workflows-mcp
```

### 2) Add to your MCP client

Example (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "workflows": {
      "command": "uvx",
      "args": ["workflows-mcp"],
      "env": {
        "WORKFLOWS_TEMPLATE_PATHS": "/path/to/your/workflows",
        "WORKFLOWS_LOG_LEVEL": "INFO",
        "WORKFLOW_SECRET_API_KEY": "your-secret-value"
      }
    }
  }
}
```

If installed with `pip`:

```json
{
  "mcpServers": {
    "workflows": {
      "command": "workflows-mcp",
      "env": {
        "WORKFLOWS_TEMPLATE_PATHS": "/path/to/your/workflows",
        "WORKFLOWS_LOG_LEVEL": "INFO",
        "WORKFLOW_SECRET_API_KEY": "your-secret-value"
      }
    }
  }
}
```

### 3) Restart your MCP client and run first calls

1. `list_workflows`
2. `get_workflow_info`
3. `execute_workflow`


## Instructions for LLM Agents

Use this call order for reliable results:

1. **Discover**: call `list_workflows`.
2. **Inspect**: call `get_workflow_info` for required inputs.
3. **Execute**: call `execute_workflow`.
4. **Track async runs** (if `mode="async"`): call `get_job_status` (or `list_jobs`).
5. **Resume interactive workflows**: call `resume_workflow` only for `paused` jobs (typically from `Prompt` blocks).
6. **Reload definitions after YAML edits**: call `reload_workflows`.

When authoring workflows, validate first:

- `validate_workflow_yaml` before `execute_inline_workflow`.
- Use `get_workflow_schema` for current schema details.
- Use the block reference for exact field names and required inputs: `docs/llm/block-reference.md`.

Async mini-flow example:

```text
execute_workflow(workflow="python-ci-pipeline", inputs={...}, mode="async")
→ returns job_id
→ get_job_status(job_id="job_...") until completed/failed/paused
→ if paused, resume_workflow(job_id="job_...", response="...")
```

## Available MCP tools (catalog + call patterns)

### Workflow discovery and execution

| Tool | When to call | Typical call pattern |
| --- | --- | --- |
| `list_workflows` | List registered workflows | `list_workflows(tags=[], format="json")` |
| `get_workflow_info` | Exploratory to confirm inputs/outputs | `get_workflow_info(workflow="name", format="json")` |
| `execute_workflow` | Run a registered workflow | `execute_workflow(workflow="name", inputs={...}, mode="sync")` |
| `execute_inline_workflow` | Test one-off YAML without registering | `execute_inline_workflow(workflow_yaml="...", inputs={...})` |
| `reload_workflows` | After editing workflow YAML files on disk | `reload_workflows()` |

### Authoring and validation

| Tool | When to call | Typical call pattern |
| --- | --- | --- |
| `get_workflow_schema` | Debugging only. Retrieve full JSON schema for authoring | `get_workflow_schema()` |
| `validate_workflow_yaml` | Validate YAML before execution | `validate_workflow_yaml(yaml_content="...")` |

### Async, queue, and interactive control

| Tool | When to call | Typical call pattern |
| --- | --- | --- |
| `get_job_status` | Poll a specific async job | `get_job_status(job_id="job_...")` |
| `list_jobs` | Find jobs by status (especially paused) | `list_jobs(status="paused", limit=100)` |
| `cancel_job` | Stop queued/running jobs | `cancel_job(job_id="job_...")` |
| `get_queue_stats` | Monitor queue health/capacity | `get_queue_stats()` |
| `resume_workflow` | Continue paused `Prompt` workflows | `resume_workflow(job_id="job_...", response="...")` |

### Memory (conditional)

| Tool | When to call | Typical call pattern |
| --- | --- | --- |
| `memory` | Unified memory query/ingest/maintenance/graph operations | `memory(operation="query", scope={...}, query={...})` |
| `project_onboard` | Current memory onboarding flow with checkpoints | `project_onboard(scope={...}, ingest={...}, max_operations=1)` |
| `project_sync` | Current memory checkpoint resume/continuation | `project_sync(checkpoint={...}, max_operations=3)` |

IMPORTANT: The `memory` tool is registered only when memory DB setup is available and valid at startup (see [below](#memory))

Memory contract highlights:

- Unified envelope: `operation` + optional `scope/query/record/graph/maintenance/response`.
- Current memory taxonomy: `scope` accepts only `palace`, `wing`, `room`, `compartment`.
- Context activation and scope defaulting:
  - Resolution precedence is `scope` → `scope_token` → `context_id` (per-field merge).
  - `scope_token` resolves from execution context `memory_scope_tokens`; `context_id` resolves from `memory_context_scopes`.
  - Responses include `resolved_scope` and `scope_source` when available.
  - Required scope by operation:
    - `query`: all four fields must resolve.
    - `ingest`: all four fields must resolve (including `compartment`).
    - `graph_upsert` with `graph.kind="place"`: all four fields must resolve.
    - `validate|supersede|archive|maintain|graph_delete|graph_upsert(kind="link")`: scope is optional.
- Temporal query semantics:
  - `operation="query"` supports either `query.as_of` OR interval `query.from/query.to` (mutually exclusive).
  - `query.mode="graph"` supports `query.as_of` only; `query.from/query.to` are rejected.
  - `operation="ingest"` with `record.format="raw"` supports `record.valid_from` and `record.valid_to` with ordering validation (`valid_from <= valid_to`).
- Strict validation: unknown/extra fields are rejected.
- Direct vs derived boundaries:
  - `operation="ingest"` is direct-only (`record.memory_tier` must be `direct`).
  - Category governance for ingest is explicit:
    - Unknown `record.categories` fail deterministically with `MEM_UNKNOWN_CATEGORY` when `record.allow_create_categories=false` (default behavior).
    - Setting `record.allow_create_categories=true` opts into category creation and allows ingest to proceed when categories are otherwise valid.
  - Derived/community artifacts are produced by maintenance flows (for example `maintenance.mode="community_refresh"`).
  - `query.mode="communities"` uses the dedicated communities strategy.
- Lifecycle semantics:
  - Archived records are excluded by default query behavior.
  - `operation="supersede"` requires `record.superseded_by`.
  - `operation="archive"` maps to forget semantics; repeating archive on already archived records is safe/idempotent.
- Graph semantics:
  - `operation="graph_upsert"` with `graph.kind="link"` is idempotent.
  - `operation="graph_delete"` returns compact delete counters (`deleted_places` for `kind="place"`, `deleted_links` for `kind="link"`); optional debug output adds diagnostics metadata.

Validation note: this ingest category behavior (`MEM_UNKNOWN_CATEGORY` with create disabled, successful ingest with `allow_create_categories=true`) was live-validated on 2026-04-21 via production-like direct MCP `memory` calls.

Direct-call JSON examples:

`query`:

```json
{
  "operation": "query",
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "query": {"mode": "search", "text": "schema epoch", "as_of": "2026-04-20T00:00:00Z", "radius": 1}
}
```

`ingest`:

```json
{
  "operation": "ingest",
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "record": {"format": "raw", "content": "Memory active", "memory_tier": "direct"}
}
```

`validate`:

```json
{
  "operation": "validate",
  "record": {"ids": ["11111111-1111-1111-1111-111111111111"]}
}
```

`supersede`:

```json
{
  "operation": "supersede",
  "record": {
    "ids": ["11111111-1111-1111-1111-111111111111"],
    "superseded_by": "22222222-2222-2222-2222-222222222222"
  }
}
```

`archive`:

```json
{
  "operation": "archive",
  "record": {"ids": ["11111111-1111-1111-1111-111111111111"]}
}
```

`maintain`:

```json
{
  "operation": "maintain",
  "maintenance": {"mode": "community_refresh"}
}
```

`graph_upsert` (`kind=place`):

```json
{
  "operation": "graph_upsert",
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "graph": {"kind": "place", "place_name": "Memory API (current)", "place_type": "feature"}
}
```

`graph_upsert` (`kind=link`):

```json
{
  "operation": "graph_upsert",
  "graph": {
    "kind": "link",
    "from": "11111111-1111-1111-1111-111111111111",
    "to": "22222222-2222-2222-2222-222222222222",
    "link_type": "depends_on"
  }
}
```

`graph_delete`:

```json
{
  "operation": "graph_delete",
  "graph": {"kind": "place", "ids": ["33333333-3333-3333-3333-333333333333"]}
}
```

`project_onboard`:

```json
{
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "ingest": {"format": "raw", "content": "Initial baseline", "memory_tier": "direct"},
  "supersede": {"ids": ["11111111-1111-1111-1111-111111111111"], "superseded_by": "22222222-2222-2222-2222-222222222222"},
  "archive": {"ids": ["33333333-3333-3333-3333-333333333333"]},
  "maintain": {"mode": "community_refresh"},
  "max_operations": 1
}
```

`project_sync`:

```json
{
  "checkpoint": {
    "version": "oss-r2",
    "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
    "plan": [{"operation": "ingest", "payload": {"format": "raw", "content": "Initial baseline", "memory_tier": "direct"}}],
    "next_index": 0,
    "completed": []
  },
  "max_operations": 3
}
```

Invalid (mutually exclusive temporal filters):

```json
{
  "operation": "query",
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "query": {
    "mode": "search",
    "text": "maintenance",
    "as_of": "2026-04-20T00:00:00Z",
    "from": "2026-04-01T00:00:00Z",
    "to": "2026-04-20T00:00:00Z"
  }
}
```

Invalid (graph query rejects interval filters):

```json
{
  "operation": "query",
  "scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
  "query": {
    "mode": "graph",
    "text": "service graph",
    "from": "2026-04-01T00:00:00Z",
    "to": "2026-04-20T00:00:00Z"
  }
}
```

Invalid (legacy taxonomy key):

```json
{
  "operation": "query",
  "scope": {"palace": "acme", "wing": "svc", "room": "component", "hall": "legacy"},
  "query": {"text": "find this", "mode": "search"}
}
```

Invalid (supersede missing required `superseded_by`):

```json
{
  "operation": "supersede",
  "record": {
    "ids": ["11111111-1111-1111-1111-111111111111"]
  }
}
```

## Configuration

### Workflow loading and execution

- `WORKFLOWS_TEMPLATE_PATHS`: Comma-separated workflow directories to load.
- `WORKFLOWS_MAX_RECURSION_DEPTH`: Max workflow composition depth (default: `50`).
- `WORKFLOWS_LOG_LEVEL`: Logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`; default: `INFO`).

### Queue and async settings

- `WORKFLOWS_IO_QUEUE_ENABLED`: Enable serialized I/O queue (default: `true`).
- `WORKFLOWS_JOB_QUEUE_ENABLED`: Enable async job queue (default: `true`).
- `WORKFLOWS_JOB_QUEUE_WORKERS`: Queue workers (default: `3`).
- `WORKFLOWS_MAX_CONCURRENT_JOBS`: Max active + queued jobs (default: `500`).
- `WORKFLOWS_JOB_TIMEOUT`: Default async timeout in seconds (default: `3600`).
- `WORKFLOWS_JOB_HISTORY_MAX`: Max retained job records (default: `1000`).
- `WORKFLOWS_JOB_HISTORY_TTL`: Job retention TTL in seconds (default: `86400`).

### Secrets and LLM config

- `WORKFLOW_SECRET_<NAME>`: Secret value exposed as `{{secrets.NAME}}`.
- `WORKFLOWS_LLM_CONFIG`: Optional path override for LLM config.

## Memory

Memory is an optional persistent storage feature that lets agents and workflows record, retrieve, and organize information across sessions. It is backed by PostgreSQL and gives each agent a structured, scoped, and temporally-aware knowledge store.

### What memory provides

- **`memory` MCP tool** — direct call interface for LLM agents to store and query information without writing workflow YAML.
- **`project_onboard` / `project_sync` MCP tools** — Current memory contract helpers for checkpointed onboarding/sync sequences.
- **`Memory` workflow block** — use inside YAML workflows to automate memory operations as part of larger pipelines.
- **Memory topology scoping** (`palace` → `wing` → `room` → `compartment`) — current memory scope keys are strict and legacy keys (for example `hall`) are rejected. Scope can be supplied directly and/or resolved from context (`scope_token`, `context_id`) using deterministic precedence.
- **Temporal tracking** — records carry `valid_from` / `valid_to` timestamps supporting point-in-time and interval queries.
- **Knowledge graph** — link memories to places, entities, or concepts and query the resulting graph.
- **Lifecycle management** — archive or supersede records without deletion; archived records are excluded from default queries.

### Retrieval strategies

Current memory behavior exposes query modes that map to retrieval strategies internally:

| Query mode / trigger | Effective strategy | Behavior |
| --- | --- | --- |
| `query.mode="search"` + `radius=0` | `palace` | Strict scoped retrieval lane (no companion lane). |
| `query.mode="search"` + `radius>=1` | `auto` | Scoped lane + optional S2 companion lane (`s2_enabled=true` by default). |
| `query.mode="hybrid"` | `auto` | Same retrieval family as `auto` with fused ranking. |
| `query.mode="context"` | `context` | Context assembly retrieval path. |
| `query.mode="graph"` | `graph` | Graph traversal/path/stats retrieval. |
| `query.mode="communities"` | `communities` | Community-focused retrieval strategy. |

Every `query` call still requires a fully resolved current memory scope (`palace/wing/room/compartment`) resolved from request and/or context sources.

#### Scope call shape (with context activation)

Scope fields can be passed directly and/or resolved from `scope_token` / `context_id`:

```json
{
  "operation": "query",
  "scope": {"palace": "acme", "wing": "my-service"},
  "scope_token": "st_auth",
  "context_id": "ctx_default",
  "query": {"text": "refresh token lifetime", "mode": "context"}
}
```

Resolution precedence is `scope` → `scope_token` → `context_id` for each field.

### Prerequisites

- PostgreSQL 13 or later, network-accessible from the server process.
- A database user with `CREATE DATABASE` rights on the admin database (typically `postgres`) if auto-create is enabled, **or** a pre-existing database that the user can connect to.

### Configuration

| Variable | Default | Required | Description |
| --- | --- | --- | --- |
| `MEMORY_DB_HOST` | — | Yes | PostgreSQL hostname or IP. Setting this variable enables memory features. |
| `MEMORY_DB_PORT` | `5432` | No | PostgreSQL port. |
| `MEMORY_DB_NAME` | `memory_db` | No | Target database name. |
| `MEMORY_DB_USER` | — | Yes | Database username. |
| `MEMORY_DB_PASSWORD` | — | Yes | Database password. |
| `MEMORY_DB_AUTO_CREATE` | `true` | No | Auto-create the target database on first boot if it does not exist. Requires the user to have `CREATE DATABASE` rights on the admin database. |
| `MEMORY_DB_ADMIN_DATABASE` | `postgres` | No | Admin database used to issue the `CREATE DATABASE` statement when auto-create is enabled. |
| `AUDIT_FAIL_CLOSED` | `false` | No | When `true`, audit-logging failures abort the entire memory operation (compliance mode). Default is log-and-continue. |

### Enabling memory

Add the following variables to your MCP client config:

```json
{
  "mcpServers": {
    "workflows": {
      "command": "uvx",
      "args": ["workflows-mcp"],
      "env": {
        "MEMORY_DB_HOST": "localhost",
        "MEMORY_DB_PORT": "5432",
        "MEMORY_DB_NAME": "memory_db",
        "MEMORY_DB_USER": "postgres",
        "MEMORY_DB_PASSWORD": "your-password"
      }
    }
  }
}
```

On first boot with `MEMORY_DB_AUTO_CREATE=true` (the default), the server creates the target database and applies the schema automatically. Restart your MCP client after adding the variables.

### Verifying memory is active

1. Restart your MCP client.
2. Call `list_workflows` — confirm the server started without errors in the client logs.
3. Check that the `memory` tool appears in the available tool list.
4. Run a test ingest:

```json
{
  "operation": "ingest",
  "scope": {"palace": "acme", "wing": "test", "room": "setup", "compartment": "smoke"},
  "record": {"format": "raw", "content": "Memory is working.", "memory_tier": "direct"}
}
```

If the tool is absent, check server logs for `MEMORY_DB_*` startup errors — the most common causes are an unreachable host, incorrect credentials, or a schema epoch mismatch.

### Schema compatibility

Memory schema versions are tracked by epoch. If the epoch in the database does not match the server version:

- Startup fails with an explicit error.
- Apply the documented migration and restart.
- No automatic destructive reset is performed. Set `MEMORY_SCHEMA_RESET_MODE` only if you intend a one-time destructive reset on a non-production instance.

---

## Workflows for users

Use registered workflows for repeatable automation, and inline workflows for experiments.

- **Registered workflows**: best for shared, reusable operations.
- **Inline workflows**: best for quick tests and prototyping.

Author workflow YAML with exact block input names from:

- `docs/llm/block-reference.md`

Example block families include `Shell`, `ReadFiles`, `HttpCall`, `LLMCall`, `Sql`, `Workflow`, `Prompt`, and `Memory`.

## Documentation map

- `README.md`: install, usage, and tool catalog.
- `docs/guides/memory-tools-cheatsheet.md`: Current memory contract quick reference, detailed guide, and examples.
- `docs/llm/block-reference.md`: exact block inputs/outputs for workflow authoring.
- `docs/TESTING.md`: test strategy and test commands.
- `ARCHITECTURE.md`: architecture overview.
- `docs/adr/`: design decisions and rationale.
- `CHANGELOG.md`: release history.

## Contributing

1. Fork the repository and create a focused branch.
2. Add or update tests with your change.
3. Run quality checks before opening a PR:

```bash
uv run pytest
uv run ruff check src/workflows_mcp/
uv run mypy src/workflows_mcp/
```

4. Describe behavior changes and config impact clearly in the PR.

## Support and community

- Issues and bug reports: https://github.com/qtsone/workflows-mcp/issues
- Project repository: https://github.com/qtsone/workflows-mcp

## License

AGPL-3.0-or-later. See [LICENSE](./LICENSE).
