# Connect CrewAI to Axiom

**Transport:** stdio (MCPServerAdapter also supports HTTP/SSE)
**Auth:** local-stdio (Phase 0)
**Status:** Untested — recipe inferred from upstream docs

CrewAI added first-class MCP support via `crewai_tools.MCPServerAdapter`.
Each adapter wraps one MCP server and exposes its tools as CrewAI
`BaseTool` subclasses that any `Agent` can use.

## Install prerequisites

```bash
pip install 'crewai[tools]>=0.86' mcp
```

Same Axiom prerequisites as the other recipes.

## Configure the connection

```python
from mcp import StdioServerParameters
from crewai import Agent, Crew, Task
from crewai_tools import MCPServerAdapter


server_params = StdioServerParameters(
    command="/absolute/path/to/.venv/bin/axi",
    args=["mcp", "serve"],
    # env=None,  # add PYTHONPATH for worktree variant
)

with MCPServerAdapter(server_params) as axiom_tools:
    print("Loaded Axiom MCP tools:")
    for t in axiom_tools:
        print(f"  {t.name}")

    diagnostician = Agent(
        role="Axiom node diagnostician",
        goal="Inspect the local Axiom node and report its hook state.",
        backstory="You use Axiom's MCP tools to read live node state.",
        tools=axiom_tools,
        verbose=True,
    )
    smoke = Task(
        description=(
            "Call axiom_node__hooks_list with no arguments and report the JSON."
        ),
        expected_output="The JSON result of axiom_node__hooks_list.",
        agent=diagnostician,
    )
    crew = Crew(agents=[diagnostician], tasks=[smoke])
    print(crew.kickoff())
```

Worktree variant:

```python
server_params = StdioServerParameters(
    command="/absolute/path/to/.venv/bin/python3",
    args=["-m", "axiom.extensions.builtins.mcp.server"],
    env={"PYTHONPATH": "/absolute/path/to/axiom-checkout/src"},
)
```

## Verify

The script above prints the tool list and the agent's task output. A
direct check (without spinning up a full Crew):

```python
from mcp import StdioServerParameters
from crewai_tools import MCPServerAdapter

params = StdioServerParameters(command="axi", args=["mcp", "serve"])
with MCPServerAdapter(params) as tools:
    hooks = next(t for t in tools if t.name == "axiom_node__hooks_list")
    print(hooks.run())
```

Expected:

```json
{
  "node": "/Users/<you>/.axiom",
  "hooks_total": 0,
  "events_observed": [],
  "by_event": {}
}
```

## Notes

- `MCPServerAdapter` is a context manager — it spawns the MCP subprocess
  on `__enter__` and tears it down on `__exit__`. Long-running Crews
  should keep the adapter alive for the whole crew lifetime, not
  per-task.
- Tools are registered with the inferred schema. CrewAI's strict-mode
  validation may reject MCP tools whose `inputSchema` uses JSON Schema
  features CrewAI doesn't yet model; report upstream if you hit one.
- For HTTP/SSE: `from mcp.client.sse import sse_client` plus the
  appropriate URL — needs Axiom Phase 5 auth.

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| Adapter blocks forever | MCP subprocess crash on init | Check stderr: run the same `command`/`args` manually |
| `KeyError: tool` | tool name mismatch | `[t.name for t in tools]` to confirm canonical names |
| Tool schema rejected | CrewAI strict mode + complex schema | Report to crewAI-tools; workaround: wrap with a CrewAI `BaseTool` subclass |

## References

- ADR-038 §D7
- CrewAI MCP docs: https://docs.crewai.com/en/mcp/overview

_Copyright (c) 2026 B-Tree Ventures, LLC. Apache-2.0 licensed._
