# Workflow integrations

Call AI, HTTP, MCP, Postgres and bound provider operations through the workflow context.

[Deploy your workflow](/deploy)

[Start for free](https://app.whenever.dev/)

## Integrations

ctx.integrations declares four ports. Everything else is added per workspace.

| Operation                                                             | Does                                                                                                                 |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `ctx.integrations.ai.generateText({ prompt, system? })`               | Returns `{ text }`. No model or length settings: the platform pins the model.                                        |
| `ctx.integrations.ai.generateText({ messages, system? })`             | Continues a conversation without tools. Returns the text, and the message to append for the next turn.               |
| `ctx.integrations.ai.generateText({ messages, tools, toolChoice? })`  | One turn of an agent loop. Returns text, or the tool calls the model chose; the workflow runs them and loops.        |
| `ctx.integrations.ai.generateImage({ prompt })`                       | Returns `{ imageUrl }` for one generated image.                                                                      |
| `ctx.integrations.http.get({ url, headers?, query? })`                | Returns `{ status, headers, body }`, with body typed unknown — narrow it with a guard.                               |
| `ctx.integrations.http.post({ url, body?, headers? })`                | The write verbs, alongside put and patch. Uncertainty on a patch is never retried automatically.                     |
| `ctx.integrations.mcp.read({ url, toolName, toolProps?, headers? })`  | Calls a read-only tool on an MCP server you name. Returns `{ structuredContent, content }`, both unknown.            |
| `ctx.integrations.mcp.write({ url, toolName, toolProps?, headers? })` | Calls a tool that may change remote state. Uncertainty here is never retried automatically.                          |
| `ctx.integrations.postgres.query({ sql, params?, maxRows? })`         | One parameterized statement in a read-only transaction. Returns `{ rows, rowCount, truncated }`; a write is refused. |

Those four are what the SDK itself declares. Every other provider operation arrives as a binding: binding an operation writes your workspace's integrations.generated.d.ts, which augments WorkflowIntegrations with that provider's member — so what a workflow can reach depends on what the workspace has bound and the owner has connected, not on what TypeScript would otherwise let you type.

The ai, http and mcp ports are credential-free, and postgres runs against the owner's stored connection, whose password your source never receives. Never read environment variables or credential values in workflow code: take settings from ctx.config, stored secrets from ctx.secrets, and everything else from a port.

Every http and mcp request names its destination in the source: an origin written as a literal, a whole URL from one ctx.config or ctx.secrets value, or — to answer whoever sent a delivery — the address that delivery carried in ctx.input, in which case the request may carry no workflow secret. An agent loop counts every model turn and every tool call against the run's call budget, so cap the turns and validate each call's arguments before you use them.

## Access and provider constraints

An available port does not bypass the destination's authentication. HTTP and MCP calls still need any credentials, permissions and provider plan required by their destination. The hosted runtime must be able to reach the endpoint; private-network-only services are not automatically reachable.

Optional AI calls happen during a run and can vary their outputs or incur runtime AI usage. Keep them distinct from the account's weekly building allowance. Model turns and tool calls count against the run's call budget, so bound an agent loop rather than assuming unlimited execution.

## Related documentation

- [Integration directory](/integrations)
- [An AI assistant workflow](/docs/ai-agent-example)
- [Deployment and Setup](/docs/deploy)
- [Runtime limits and responsibilities](/docs/runtime-limits)
