Skip to main content

CrewAI quickstart — governed agent in 15 minutes

Cordum v2.9+ CrewAI 0.30+ Python 3.11+ 15 min

Route every CrewAI tool call through Cordum's MCP bridge so you get scope-filtered tool visibility, per-tool approval gates, and tamper-evident audit — all behind a one-line adapter import.

What you'll build

A CrewAI Agent whose tools come from cordum-mcp-bridge. After a successful call, the Cordum dashboard's Policy Decision Log shows one mcp.tool_invocation event with decision=allow, latency_ms, and the redacted arguments. When you seed a deny-policy on the same tool and re-run, the adapter surfaces AdapterToolCallError wrapping the gateway's [POLICY DENIED] reason — no change to your CrewAI code.

Before you start

  • Python 3.11+ (3.9 and 3.10 also supported; 3.12 is CI-covered).
  • A running Cordum instance. Clone github.com/cordum/cordum and run make dev-up — brings up gateway + scheduler + NATS + Redis on localhost.
  • CORDUM_API_KEY exported from your Cordum admin account (cordumctl auth login or copy from .env).
  • cordum-mcp-bridge on your $PATH:
    cd cordum-packs/packs/mcp-bridge
    go install ./cmd/cordum-mcp-bridge

:::note Windows / MSYS Use Unix shell syntax (forward slashes, /dev/null). The adapter never hard-codes a path separator — shutil.which finds cordum-mcp-bridge via $PATH on every supported platform. :::

1. Install

cordum-adapters is not yet on PyPI (tracked in task-386f52f4). Clone the source repo and install from the local checkout until the first release ships:

git clone https://github.com/cordum-io/cordum-packs.git
pip install "./cordum-packs/integrations/agent-adapters[crewai]"

Pip treats a local directory as a project root, so extras resolve against the checkout's pyproject.toml without relying on pip's VCS+subdirectory fragment (which does not forward the fragment into the build isolation step on all supported pip versions).

The [crewai] extra pulls crewai>=0.30, crewai-tools>=0.1, and pydantic>=2.0. Base cordum-adapters has no framework dependencies — you only pay for the extras you pick.

Once the PyPI publish lands, this becomes pip install "cordum-adapters[crewai]".

2. Configure — connect to the bridge

import os
from cordum_agent_adapters.mcp_client import McpStdioClient

client = McpStdioClient(
command=["cordum-mcp-bridge"],
env={
**os.environ,
"CORDUM_GATEWAY_URL": "http://localhost:8081",
"CORDUM_API_KEY": os.environ["CORDUM_API_KEY"],
"CORDUM_NATS_URL": "nats://localhost:4222",
"CORDUM_REDIS_URL": "redis://localhost:6379",
},
)
print([tool["name"] for tool in client.list_tools()])
# ['cordum.workflow.list', 'cordum.workflow.run', 'cordum.dlq.retry', ...]

The client owns the bridge subprocess — call client.close() on shutdown (a try/finally or an atexit handler is fine).

3. Build a governed CrewAI agent

from crewai import Agent, Crew, Task
from cordum_agent_adapters.crewai import build_crewai_tools

tools = build_crewai_tools(client)

researcher = Agent(
role="Ops Researcher",
goal="Find the most recent DLQ entries and summarise them.",
backstory="You run Cordum's operations crew.",
tools=tools,
allow_delegation=False,
)

task = Task(
description="List the last 5 DLQ jobs and their fail reasons.",
expected_output="A short Markdown bullet list.",
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)

The same tools list is what a non-governed CrewAI agent would use; the only difference is build_crewai_tools(client) instead of a hand-rolled Tool(...).

4. Run and verify governance

# Start the compose stack if you haven't.
cd cordum && make dev-up

# Run the script above:
python crewai_quickstart.py

Open the Cordum dashboard → Policy Decision Log. Filter by event_type=mcp.tool_invocation and you'll see one row per tool call: the tool name, decision, latency, and the args_redacted JSON with any secrets scrubbed.

Seed a deny policy and watch the adapter recover

# Deny cordum.dlq.retry for the test tenant.
cordumctl policy bundle create --tenant=default --yaml - <<'YAML'
id: deny-dlq-retry
rules:
- when: {tool: "cordum.dlq.retry"}
decision: deny
reason: "manual review required"
YAML

Re-run the script. The agent sees an AdapterToolCallError wrapping the gateway's [POLICY DENIED] reason on the next turn — CrewAI receives the error as a tool-result message, so the LLM can apologise, try a different approach, or escalate. No code change to the CrewAI agent.

What's next