workflows-mcp
Run YAML workflows as MCP tools so agents can automate real tasks with one server.
README
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 (
Promptblocks) 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+.
uv pip install workflows-mcp
or:
pip install workflows-mcp
2) Add to your MCP client
Example (claude_desktop_config.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:
{
"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
list_workflowsget_workflow_infoexecute_workflow
Instructions for LLM Agents
Use this call order for reliable results:
- Discover: call
list_workflows. - Inspect: call
get_workflow_infofor required inputs. - Execute: call
execute_workflow. - Track async runs (if
mode="async"): callget_job_status(orlist_jobs). - Resume interactive workflows: call
resume_workflowonly forpausedjobs (typically fromPromptblocks). - Reload definitions after YAML edits: call
reload_workflows.
When authoring workflows, validate first:
validate_workflow_yamlbeforeexecute_inline_workflow.- Use
get_workflow_schemafor current schema details. - Use the block reference for exact field names and required inputs:
docs/llm/block-reference.md.
Async mini-flow example:
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 contract highlights:
- Unified envelope:
operation+ optionalscope/query/record/graph/maintenance/response. - Current memory taxonomy:
scopeaccepts onlypalace,wing,room,compartment. - Context activation and scope defaulting:
- Resolution precedence is
scope→scope_token→context_id(per-field merge). scope_tokenresolves from execution contextmemory_scope_tokens;context_idresolves frommemory_context_scopes.- Responses include
resolved_scopeandscope_sourcewhen available. - Required scope by operation:
query: all four fields must resolve.ingest: all four fields must resolve (includingcompartment).graph_upsertwithgraph.kind="place": all four fields must resolve.validate|supersede|archive|maintain|graph_delete|graph_upsert(kind="link"): scope is optional.
- Resolution precedence is
- Temporal query semantics:
operation="query"supports eitherquery.as_ofOR intervalquery.from/query.to(mutually exclusive).query.mode="graph"supportsquery.as_ofonly;query.from/query.toare rejected.operation="ingest"withrecord.format="raw"supportsrecord.valid_fromandrecord.valid_towith ordering validation (valid_from <= valid_to).
- Strict validation: unknown/extra fields are rejected.
- Direct vs derived boundaries:
operation="ingest"is direct-only (record.memory_tiermust bedirect).- Category governance for ingest is explicit:
- Unknown
record.categoriesfail deterministically withMEM_UNKNOWN_CATEGORYwhenrecord.allow_create_categories=false(default behavior). - Setting
record.allow_create_categories=trueopts into category creation and allows ingest to proceed when categories are otherwise valid.
- Unknown
- 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"requiresrecord.superseded_by.operation="archive"maps to forget semantics; repeating archive on already archived records is safe/idempotent.
- Graph semantics:
operation="graph_upsert"withgraph.kind="link"is idempotent.operation="graph_delete"returns compact delete counters (deleted_placesforkind="place",deleted_linksforkind="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:
{
"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:
{
"operation": "ingest",
"scope": {"palace": "acme", "wing": "workflows", "room": "memory-engine", "compartment": "contract-r2"},
"record": {"format": "raw", "content": "Memory active", "memory_tier": "direct"}
}
validate:
{
"operation": "validate",
"record": {"ids": ["11111111-1111-1111-1111-111111111111"]}
}
supersede:
{
"operation": "supersede",
"record": {
"ids": ["11111111-1111-1111-1111-111111111111"],
"superseded_by": "22222222-2222-2222-2222-222222222222"
}
}
archive:
{
"operation": "archive",
"record": {"ids": ["11111111-1111-1111-1111-111111111111"]}
}
maintain:
{
"operation": "maintain",
"maintenance": {"mode": "community_refresh"}
}
graph_upsert (kind=place):
{
"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):
{
"operation": "graph_upsert",
"graph": {
"kind": "link",
"from": "11111111-1111-1111-1111-111111111111",
"to": "22222222-2222-2222-2222-222222222222",
"link_type": "depends_on"
}
}
graph_delete:
{
"operation": "graph_delete",
"graph": {"kind": "place", "ids": ["33333333-3333-3333-3333-333333333333"]}
}
project_onboard:
{
"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:
{
"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):
{
"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):
{
"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):
{
"operation": "query",
"scope": {"palace": "acme", "wing": "svc", "room": "component", "hall": "legacy"},
"query": {"text": "find this", "mode": "search"}
}
Invalid (supersede missing required superseded_by):
{
"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
memoryMCP tool — direct call interface for LLM agents to store and query information without writing workflow YAML.project_onboard/project_syncMCP tools — Current memory contract helpers for checkpointed onboarding/sync sequences.Memoryworkflow 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 examplehall) 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_totimestamps 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:
{
"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 DATABASErights on the admin database (typicallypostgres) 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:
{
"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
- Restart your MCP client.
- Call
list_workflows— confirm the server started without errors in the client logs. - Check that the
memorytool appears in the available tool list. - Run a test ingest:
{
"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_MODEonly 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
- Fork the repository and create a focused branch.
- Add or update tests with your change.
- Run quality checks before opening a PR:
uv run pytest
uv run ruff check src/workflows_mcp/
uv run mypy src/workflows_mcp/
- 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.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.