Connections
A connection is a credentialed link to an external service that your agents and workflows call — a REST API, an OpenAPI spec, a Model Context Protocol (MCP) server, an AI model provider, or a messaging account like Gmail or Telegram. Connections are outbound: a workflow reaches out, gets a result, and keeps going. Manage them all from the Connections hub. Every credential is encrypted at rest.
Overview
The Connections hub is the single home for every external credential your workspace uses. Each connection exposes one or more tools that agents and workflow Tool nodes can call, using the slug.operation naming convention. Connections come in two transports:
Any REST API — defined manually or imported from an OpenAPI spec. Each API operation becomes an individual tool your agents can call.
Any server implementing the Model Context Protocol (Streamable HTTP or SSE transport). Every tool the server exposes is discovered and made available automatically.
AI model providers (OpenAI, Anthropic, Gemini), search tools, and messaging accounts (Gmail, Telegram bots) are also managed here as connections — they share the same encrypted credential store. Once added, every connection's tools appear alongside built-in tools in the agent tool picker and the workflow Tool node inspector.
Service types
When you create a connection you pick a service type. It determines the transport, the available auth methods, and how tools are defined:
| Service type | Transport | What it is |
|---|---|---|
| http | http | A generic REST API with operations you define by hand. |
| openapi | http | A REST API imported from an OpenAPI 3.x / Swagger 2.x spec. |
| mcp | mcp | A Model Context Protocol server; tools are auto-discovered. |
| gmail | http | A Gmail account (service account or personal OAuth). |
| telegram | http | A Telegram bot token for sending messages. |
HTTP & OpenAPI
Create an HTTP connection from Connections → New Connection. For a generic REST API choose HTTP API; to import a spec choose OpenAPI. You will set:
- Name & slug — the slug is used as the tool prefix (e.g.
github→ tools namedgithub.create_issue). - Base URL — the root URL of the API.
- Auth type — none, API key (header or query), Bearer token, or Basic auth.
- Operations — each operation has a name, HTTP method, path, and optional input/output parameter schemas.
Operation path templating
Path and query parameters use {{param}} syntax and are filled from the agent's tool call arguments at runtime:
GET /repos/{{owner}}/{{repo}}/issues/{{number}}Importing a spec
The OpenAPI service type lets the wizard do the work for you:
- Choose OpenAPI in the New Connection wizard.
- Paste the spec as JSON or YAML, or upload the file. The importer extracts
servers[0]as the base URL,securitySchemesas the auth type, and all paths as operations. - Review and edit the parsed operations, adjust parameter schemas if needed, then save.
MCP servers
Chatterfly connects to MCP servers using Streamable HTTP or SSEtransport. The server's tools/list response defines all available tools.
- In Connections → New Connection, choose the MCP Server service type.
- Enter the MCP server URL (e.g.
https://mcp.example.com/sse) and configure authentication if needed. - The backend connects to the server, calls
tools/list, and previews the discovered tool definitions. - Review the discovered tools and save the connection.
MCP authentication
MCP connections support the same auth types as HTTP connections:
- None — no authentication (public MCP servers).
- API Key — sent as a header (default
X-API-Key, configurable). - Bearer — sent as
Authorization: Bearer <token>. - OAuth2 — for servers requiring OAuth tokens; the access token is sent as a Bearer header. For MCP servers that support OAuth 2.1 (protected-resource + authorization-server metadata, dynamic client registration, PKCE), a "Sign in to this MCP server" button drives the whole flow — no manual client ID/secret entry required.
Session handling & tool results
Chatterfly speaks the MCP spec directly: an initialize handshake negotiates the protocol version and opens a session (Mcp-Session-Id), reused across calls and reestablished automatically once it expires. Tool results are parsed as a full CallToolResult — structuredContent is preferred when present, isError: true is surfaced as a genuine tool error, and image/audio content is uploaded as a run artifact rather than inlined.
Keeping tools fresh
MCP servers can add, remove, or change tools after a connection is saved. Use the Refresh toolsaction on the connection's edit page to re-run discovery on demand — it updates the discovered operation list and clears any stale discovery_error. If the server is unreachable or returns an error during discovery, the connection keeps its last-known tools and shows the discovery error rather than failing closed.
Tool naming convention
Every connection tool follows the slug.operation format:
| Connection slug | Operation name | Tool name used in config |
|---|---|---|
| github | create_issue | github.create_issue |
| stripe | charge_card | stripe.charge_card |
| my_mcp | web_search | my_mcp.web_search |
Slugs are unique within your workspace. If you rename or delete a connection, all references to its tools in deployed workflows will fail at runtime — update them before deleting.
Using tools in agents
Open an agent in Agents. The tool picker shows two sections — Standard tools (built-in) and Connections (your HTTP/MCP tools). Select any combination.
Alternatively, specify tools directly in the agent JSON:
{
"name": "Support Agent",
"tools": [
"web_search",
"github.create_issue",
"stripe.retrieve_customer"
]
}The agent runner resolves built-in tool names from the registry first; if no match is found, it parses the name as slug.operation and looks up the connection in the database.
Wildcard binding
Instead of listing every operation, bind an entire connection with { "tool": "*", "connection": "<slug>" }. It expands to every operation that connection currently exposes — useful for MCP servers whose tool list changes over time. Add exclude to drop specific operations:
{
"tools": [
{ "tool": "*", "connection": "eng-github" },
{ "tool": "*", "connection": "docs-mcp", "exclude": ["delete_page"] }
]
}For MCP connections, tool call results are parsed as a full CallToolResult: structuredContent is used directly when the server provides it, isError: true surfaces as a real tool error the agent can react to, and image/audio content is uploaded as a run artifact rather than inlined. MCP elicitation (a server asking mid-call for more input) is not yet supported.
knowledge bindings — a scoped search tool or pre-retrieved context.Using tools in workflows
Add a Tool node to your workflow in the visual editor. In the Tool Inspector, set tool_name to the full slug.operation string:
{
"id": "create-ticket",
"type": "tool",
"tool_name": "github.create_issue",
"input": {
"owner": "acme",
"repo": "support",
"title": "{{steps.triage.output.summary}}"
}
}Tool input values support {{path.to.value}} template expressions that are resolved from workflow state at execution time. The node runs, captures the response, and the workflow advances — it does not wait for a human ( that is what a surface does).
Fulfillment
Fulfillment decides where the credentials come from when a workflow uses a connection. Choose one when you create or edit it:
| Fulfillment | Label | Where credentials come from |
|---|---|---|
| static | Static | Stored on the connection and encrypted at rest; shared across every run. |
| caller | Per-run | The caller passes credentials when starting a run — useful for personal accounts. |
| participant | Per-participant | Collected from a participant during onboarding; requires a participant role. |
participant, set a participant role (e.g. customer). Only participants with that role are asked to provide credentials during onboarding.Deploy-time bindings
The connection value a Tool or Agent node carries is a logical requirement name, not a hard pointer. At runtime it resolves in two steps: the deployment's connection_bindings map first, then a direct match against a workspace connection with the same slug. A deployment with no bindings behaves exactly as before.
Bindings let one workflow definition use different concrete connections per deployment — sandbox keys in staging and live keys in production, or one deployment per client, each bound to that client's credentials — without editing the definition:
# API
POST /api/management/workflows/{id}/deploy
{ "environment": "production",
"connection_bindings": { "email": "client-a-gmail" } }
# CLI
chatterfly deploy workflow.json --environment production \
--bind email=client-a-gmailCredential management
Chatterfly supports the following authentication types for HTTP connections:
| Auth type | How credentials are sent |
|---|---|
| none | No authentication header is added. |
| api_key_header | Custom header (e.g. X-Api-Key: <key>). |
| api_key_query | Query parameter appended to every request URL. |
| bearer | Authorization: Bearer <token> header. |
| basic | Authorization: Basic <base64(user:pass)> header. |
Storage & encryption
All credential values are encrypted with AES-256-GCM using the INTEGRATION_ENCRYPTION_KEY environment variable before being stored in the database. They are decrypted in-memory at execution time only and are never returned in any API response.
SSRF protection
The connection executor rejects requests targeting private, loopback, or link-local IP ranges (RFC1918, 127.0.0.0/8, 169.254.0.0/16, etc.) to prevent server-side request forgery.
Personal account connections
Connections with caller (per-run) fulfillment use the credentials of whoever triggers the run. Platform users pre-authorize their accounts once under Settings → My Accounts; stored credentials are then injected automatically whenever they trigger a run — no tokens are pasted into run dialogs.
Permission tiers
OAuth providers expose capability tiers so users grant only the access a workflow needs — for example Gmail offers send, read, and full tiers, each mapping to specific OAuth scopes. The tiers selected at connect time determine the scopes requested during the provider consent flow, and connected cards show which tiers were granted.
Configuring providers (operators)
Each OAuth resource provider needs a workspace-owned client. Workspace admins configure and rotate it under Workspace settings.
Resource apps are tenant-scoped and never implicitly reuse the platform's login OAuth credentials.
Register this redirect URI with the OAuth provider:
<APP_URL>/api/auth/connect/<provider>/callbackgmail, github — so the Gmail callback is /api/auth/connect/gmail/callback.Connect flows use an opaque, single-use CSRF state and S256 PKCE. Requested scopes are derived from the provider capability catalog and checked against the token response before storage. Personal account identity is resolved from the provider API, and OAuth grants can only be stored through a backend route that requires both the user session and the frontend server's HMAC signature.
Managing connected accounts
Once connected, accounts can be managed from Settings → My Accounts:
- Test connection— Verify the stored credentials are still valid by calling the provider's API.
- Update permissions — Re-authenticate to add or change permission tiers. This triggers the OAuth consent screen again.
- Switch account — Connect a different account from the same provider (e.g., use a different Gmail address). Only supported by providers with an account-picker prompt (Gmail, Google services). GitHub does not support this.
- Disconnect — Remove the provider grant and then remove the stored credentials. If provider revocation is temporarily unavailable, the encrypted local grant is retained so the revocation can be retried safely.
Multiple accounts
You can connect multiple accounts from the same provider using aliases. Each alias is a named credential slot — for example, you might have a “work” and “personal” Gmail account:
- Connect your first account normally — it uses the
defaultalias. - Click Add accounton the provider card and enter an alias name (e.g., “work”).
- Complete the OAuth flow with a different account.
When triggering a run that requires caller-fulfillment connections, if you have multiple accounts for a required provider, a dropdown lets you choose which account to use.
Participant connection management (widget)
Participants in widget sessions can also manage their connected accounts. The onboarding panel shows connected accounts and offers “Switch” (if supported) and “Disconnect” buttons. This allows participants to change accounts mid-session if needed — for example, switching from a personal to a work email. Participant disconnect also revokes OAuth access before a version-fenced local deletion, so a concurrent reconnect is not overwritten.
AI providers & platform services
API keys for AI model providers and built-in tools are managed in an encrypted database registry — not environment variables. Platform operators set platform-wide keys under Platform Admin → Service Credentials, and workspace admins can bring their own keys for overridable services under Settings → Workspace → AI & Services.
Services
| Service | Kind | Tenant-overridable |
|---|---|---|
| openai | LLM provider | Yes |
| anthropic | LLM provider | Yes |
| gemini | LLM provider (also voice & embeddings) | Yes |
| brave | Web & news search tool | Yes |
| telegram | Messaging channel bot token | No |
Resolution precedence
For each request, the key is resolved in order: your workspace key (if the service is tenant-overridable and you saved one) → platform key → a clear “not configured” error. There is no environment-variable fallback for these services.
Write-only secrets
Keys are encrypted with AES-256-GCM before storage and are never returned by any API. When editing an existing credential, leaving a field blank keeps the current value — enter a new value only to rotate it. Removing your workspace key reverts the service to the platform key.
