# Use Apideck with CrewAI

Give a crew a narrow invoice-check tool. Customer selection and connector access remain application decisions, not tasks delegated to the crew.

[Open the runnable Python example](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks/crewai_example.py) · [Compare framework guides](/guides/ai-frameworks)

## Start with a local check

Use Python 3.12 and [uv](https://docs.astral.sh/uv/). Download or clone the [example directory](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks) with its shared helper files. Python scripts declare exact dependency versions for uv; the Node example includes a lockfile. These dependencies belong to the example, not your frontend bundle.

```bash
cd examples/ai-frameworks
uv run --python 3.12 crewai_example.py
```

The default mode runs the framework wiring against a local fixture. It makes no Apideck request and needs no model key. Expected output:

```json
{"status":"fixture","records":1,"has_more":false}
```

This proves the example can load and invoke its tool or graph. It does **not** verify customer access or model behavior. See the [verification record](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks/VERIFICATION.md) for the exact checks and limits.

## Connect a customer

[Create a Vault connection](/guides/vault) for your sandbox customer. Confirm the selected connector supports [listing accounting invoices](/apis/accounting/reference/invoices/invoicesAll). Set these server-side environment variables in the example process:

| Variable | Purpose |
| --- | --- |
| `APIDECK_API_KEY` | Your application API key; inject it through an untracked environment or secret manager |
| `APIDECK_APP_ID` | The application that owns the key |
| `APIDECK_CONSUMER_ID` | Your authenticated customer's consumer |
| `APIDECK_SERVICE_ID` | The connector, such as `xero` |

Resolve the consumer from your application's authenticated user. Do not let the model choose a consumer or put credentials in a prompt, public URL or browser bundle.

These examples use **Apideck MCP** at `https://mcp.apideck.dev/mcp?scopes=read&lock_identity=true`. The MCP-specific key header is `x-apideck-api-key`. Read scope and identity locking require server 0.20.1 or later. [Docs MCP](/mcp#docs-mcp) serves documentation; it does not execute connected API operations and needs no Apideck key.

## Discover and validate the operation

```bash
uv run --python 3.12 crewai_example.py --discover
```

The helper loads the dynamic server tools, searches accounting invoices with `list_tools`, then checks `accounting-invoices-all` through `describe_tool_input`. It validates `limit: 1` and `fields: "id"` against the returned schema before execution. Discovery returns `schema_verified` with `ledger_access_verified: false`; a listed operation is not proof that your connector supports it.

## Read one invoice

After checking the customer and connector, explicitly run:

```bash
uv run --python 3.12 crewai_example.py --read
```

This makes one bounded downstream request. The summary contains `status`, `records` (zero or one), and `has_more`. Invoice identifiers, payloads and cursors are not printed or passed to a model. The sample does not follow pagination or retry failures.

Verify the consumer, connector and request in [Logs](/logs). Zero records is a valid result, but does not prove you selected the intended account. The example has a 60-second CLI deadline; a timeout is not evidence that the server never executed the request.

## Add it to your agent

The sample implements `BaseTool` with synchronous and asynchronous entry points. Give the returned tool to the intended agent only, disable delegation for this bounded check and apply crew iteration/time limits. A fresh reader allows one call across both entry points. Telemetry is disabled in the example before CrewAI is imported.

The following wiring uses files from the sample directory. Agent construction is shown separately from the offline check; model-driven execution needs provider configuration and has not been live-tested here.

```python
from common import make_reader
from crewai_example import build_tool
from crewai import Agent

agent = Agent(
    role="Invoice checker",
    goal="Check for one invoice and report the tool result.",
    backstory="You only inspect the customer selected by the application.",
    tools=[build_tool(make_reader())],
    allow_delegation=False,
    max_iter=3,
)
```

Keep the shared helper alongside the example. Its fixed operation and argument-free tool prevent the model from widening the requested fields or selecting another customer. The general MCP discovery `scope` filter only narrows search results; use server scope, identity controls and application authorization for execution restrictions.

The sample's one-attempt budget is in memory. A process restart resets it. Production workers need durable request state when retries or restarts could replay an operation. Keep raw MCP payloads out of provider tracing and logs; only the sanitized tool result should enter model context.

## Recover deliberately

| Result | Action |
| --- | --- |
| Missing environment | Set all four values in the same server process |
| Schema or tool mismatch | Check the server mode and pinned framework versions; do not guess input fields |
| 401 | Check key/application pairing and reconnect the customer where needed |
| 403 | Ask the customer's administrator to grant the required permission |
| 429 | Inspect retry guidance; this example stops rather than retrying automatically |
| Timeout or uncertain result | Inspect parent and child requests in Logs before starting another attempt |

See [MCP verification and recovery](/guides/mcp-verification-and-recovery) for discovery, execution and revocation checks. Removing a client config does not revoke the underlying key or provider connection.

## Frequently asked questions

### Does the default check use a model?

No. It exercises the framework's tool or graph interface with a fixture. A model-driven agent needs its provider configuration and separate evaluation.

### Can I use this with CRM or HRIS?

Yes, the architecture applies to other APIs. Discover the required operation, inspect its schema and create a separate bounded tool for it. This particular sample only reads accounting invoices; it is not a compatibility claim for every connector.

### Is this a benchmark result?

No. Connection checks establish integration behavior. Model accuracy, latency and token/cost comparisons need a separate controlled evaluation; the Experience Lab does not yet have scored runs for this framework example.

Continue with [the month-end close agent](/guides/month-end-close-agent), [security and data handling](/guides/security-and-data-handling), or the [official CrewAI documentation](https://docs.crewai.com/en/learn/create-custom-tools).
