Agents

MCP channels

Publish agents and selected workflows through authenticated MCP endpoints for external assistants.

A platform: mcp channel publishes an agent, selected workflows, or both through one authenticated MCP endpoint. External assistants can call your business workflows directly and retrieve their results. Add an agent when customers also need a conversation with a Swirls assistant.

A channel references a top-level connector block for inbound OAuth. Workflow publication is explicit, and each credential needs a matching workflow grant. An mcp block serves the other direction: it gives a Swirls agent tools from an external server.

Swirls remains your backend. Use its managed MCP channels for declared workflows, or build your own MCP server when your application needs custom tool composition or authentication.

Publish workflows

// Managed MCP example. Assign department=sales to a connector credential in Cloud.
// This workflow prepares a draft; it does not save or send a quote.
connector customer_access {
  label: "Customer access"
}

workflow prepare_quote {
  label: "Prepare a quote"
  description: "Calculate a draft quote from an item price and quantity. Does not save or send the quote."
  root {
    type: code
    inputSchema: @json {
      {
        "type": "object",
        "properties": {
          "item": { "type": "string", "minLength": 1 },
          "unit_price_cents": { "type": "integer", "minimum": 0, "maximum": 100000000 },
          "quantity": { "type": "integer", "minimum": 1, "maximum": 10000 }
        },
        "required": ["item", "unit_price_cents", "quantity"],
        "additionalProperties": false
      }
    }
    code: @ts {
      const { item, unit_price_cents, quantity } = context.nodes.root.input
      return { item, quantity, total_cents: unit_price_cents * quantity, status: "draft" }
    }
  }
}

channel sales_operations {
  label: "Sales operations"
  platform: mcp
  connector: customer_access
  workflows: [prepare_quote]
}

role sales {
  match { department: "sales" }
}

policy {
  allow sales -> workflow prepare_quote
}

Save this complete example as sales.swirls, validate it with swirls doctor, then deploy it with swirls deploy. It calculates a draft quote without saving or sending it. Add other declared workflows to the channel’s workflows list when needed.

Each published workflow needs a description and an object inputSchema on its root node. The workflow name becomes the tool name; its label, description, and root input schema become the tool's metadata. An empty object schema is valid for a workflow with no arguments. Names send_message and get_execution are reserved.

On the project's Connectors page, mint or edit the customer's credential. An organization owner or admin assigns department the value sales under Access attributes. Credentials created through the consent flow start without attributes; an admin can add them afterward. Attributes are managed in Cloud, never supplied in tool arguments.

The customer sees only published workflows granted by their matching roles. deny sales -> workflow prepare_quote overrides an allow grant. An agent's own tools are never automatically published, and an agent grant does not grant direct workflow access.

Calling prepare_quote validates the arguments, checks execution credits, and starts a durable Swirls execution. The result includes execution_id. The assistant calls get_execution({ execution_id }) for status and the completed output. This reads only runs started by the same credential on the same channel, while the workflow remains published and granted. Reviews still happen through Swirls; the MCP tool cannot approve them.

If submission returns submission_unknown, use the returned ID to check status. Starting the workflow again creates a separate execution and may duplicate its effects. If the run makes no progress, ask the project administrator to investigate before retrying.

If submission returns failed with an execution ID, the workflow could not be started and the run is marked Failed. Ask the project administrator to resolve the submission error before retrying.

Add agent: sales_assistant and allow sales -> agent sales_assistant to expose send_message alongside workflow tools. Agent-only channels retain their existing connector-based access. On mixed channels, agent access also requires a matching agent grant.

A direct workflow grant does not grant agent access inside that workflow. If the workflow invokes an agent, grant that agent separately through the same policy.

Workflow tool results

Workflow tools return structured data and a text representation of the same result. Starting work and reading its result are separate calls:

ResultNext step
running with execution_idPoll get_execution with that ID.
submission_unknown with execution_idPoll the existing run; investigate a stalled run before starting another.
failed with execution_id when starting a workflowThe workflow did not start. Ask the project administrator to resolve the submission error before retrying.
invalid_inputCorrect the arguments using the returned validation details.
denied or unknown_toolCheck current publication, credential attributes, and policy grants.
billing_hold or rate_limitedResolve the execution-credit limit or wait for the returned retry interval.

get_execution returns the workflow's current status and includes output when completed. It returns not_found for an execution the credential cannot read. Internal node inputs, traces, and raw exception details stay in Swirls.

The connector block

A connector block declares a Swirls-managed inbound OAuth application: the application external MCP clients authenticate against to reach your published agents and workflows. It carries display metadata only. There is no type: field; the connector keyword identifies the block.

connector client_portal {
  label: "Client portal"
  description: "Inbound OAuth application external MCP clients authenticate against"
}

Field reference

FieldTypeRequiredDescription
labelstringNoDisplay label for the connector application, shown on the Connectors page in Swirls Cloud.
descriptionstringNoDescription shown on the Connectors page.

There are no required fields. The block name is the application handle. Names must match ^[a-zA-Z0-9_]+$ and be unique across every file in the project. Unknown keys are rejected.

connector is not connection. A connection block is outbound OAuth to a third-party SaaS. A connector block is inbound: it is what external clients authenticate against to reach capabilities published on your channels. See connector vs connection vs mcp block below.

The channel block: platform: mcp

A platform: mcp channel binds its published capabilities to a connector and becomes one MCP endpoint. An agent-only channel looks like this:

connector client_portal {
  label: "Client portal"
  description: "Inbound OAuth application external MCP clients authenticate against"
}

channel finance {
  label: "Finance agent (MCP)"
  platform: mcp
  agent: finance_guy
  connector: client_portal
}

Field reference

FieldTypeRequiredDescription
platformenumYesSet to mcp.
agentidentifierConditionalOptional when workflows is nonempty. Exposes send_message.
workflowsidentifier listConditionalWorkflows published as tools. Required when no agent is declared.
connectoridentifierYes, on platform: mcpName of a top-level connector block naming the inbound OAuth application.
labelstringNoBecomes the MCP server's advertised name.
descriptionstringNoBecomes the MCP server's advertised description.

The pairing rule

The channel validator binds connector: and platform: mcp together:

  • platform: mcp requires connector:. An MCP channel must name a declared connector block. Missing it is an error.
  • platform: mcp forbids connection:. A connection is outbound OAuth to a third party; an MCP channel is inbound. Use connector: instead.
  • platform: mcp forbids mode:. mode (mention/dm/all) routes chat-platform events and has no meaning for MCP.
  • Non-MCP platforms forbid connector:. connector: is valid only on platform: mcp channels. On slack, linear, discord, or web, it is an error; those use connection: for outbound credentials.

The channel label and description are what the external client sees when it lists the server.

One connector, many channels

A connector is a credential scope, not an endpoint. One connector can front several channels, and each channel is its own MCP server with its own published capabilities. For example, these channels expose different agents:

connector client_portal {
  label: "Client portal"
}

channel finance {
  label: "Finance agent (MCP)"
  platform: mcp
  agent: finance_guy
  connector: client_portal
}

channel product {
  label: "Product agent (MCP)"
  platform: mcp
  agent: product_guy
  connector: client_portal
}

A credential minted under client_portal can authenticate to the channels that reference it. In this agent-only example, the client can connect to both finance and product. Workflow tools and mixed-channel agent tools additionally require matching policy grants.

MCP channels are addressed by name. Several channels may expose the same agent or workflows with different publication lists and connector bindings.

Choose how clients reach your agents:

  • One channel per agent. The client sees a suite of named agents in its connector list, each its own endpoint. Use this when the client should pick which specialist to talk to.
  • One channel fronting a concierge agent with a team:. A single endpoint, a single agent, and the agent delegates to subagents behind the scenes. Use this when the client should talk to one assistant and let it route internally. See Subagent teams.
agent concierge {
  label: "Concierge"
  secrets: vendor_keys
  model: "openai/gpt-4o-mini"
  team: [finance_guy, product_guy]
  system: @ts {
    return "You coordinate specialists. Route the question to the right team member."
  }
}

channel concierge_mcp {
  label: "Concierge (MCP)"
  platform: mcp
  agent: concierge
  connector: client_portal
}

Agent conversations

An agent is exposed through the send_message tool. Its internal tools stay behind the agent. Calling it starts or resumes a conversation with the agent and returns its reply, the same turn pipeline dashboard chat and Slack use. The agent's workflow tools, skills, and any mcp: slots it consumes stay behind the turn. Only workflows explicitly listed on the channel can also be called directly.

Deploy, then connect

The .swirls file never carries a client ID, a secret, or a token. The split is declare-in-git, credential-in-Cloud, the same posture as connections and MCP servers.

Deploy with git push or swirls deploy. Deploy provisions one OAuth application in Swirls Cloud per connector block. Every channel referencing it appears on the connector's page.

There are two ways a client gets access:

  • Members of your organization connect self-serve. Claude Code and Claude Desktop register themselves with Swirls Cloud, and the member approves access in the browser: sign in, choose the project and connector, and approve. The approval creates a named credential you can see and revoke on the Connectors page.
  • External clients get a minted credential. On the project Connectors page, mint a named credential for the end client, for example "Acme Corp". The page returns a client ID and a client secret.

For minted credentials:

  1. The secret is shown once. Copy it immediately; Swirls never echoes or logs it again. If you lose it, revoke the credential and mint a new one.
  2. Register the client's redirect URI when you mint the credential. The end client's tool shows this as part of adding a custom connector; without it, the authorization-code flow cannot complete.

Every credential is revocable. Revoking one on the Connectors page cuts that client off immediately, without touching any other credential, channel, or agent.

Connect from a client

Each channel's endpoint is:

https://chat.swirls.ai/chat/mcp/:projectId/:channelName

Org members need only this URL. External end clients need it plus the client ID and secret you minted for them.

Claude Code

claude mcp add --transport http <name> https://chat.swirls.ai/chat/mcp/:projectId/:channelName

Then run /mcp and authenticate. Claude Code registers itself and opens a browser. Sign in, choose the project and connector, and approve. This works for members of the organization that owns the project.

External clients connect with a minted credential instead:

claude mcp add --transport http \
  --client-id <clientId> --client-secret --callback-port 8080 \
  <name> https://chat.swirls.ai/chat/mcp/:projectId/:channelName

The credential needs http://localhost:8080/callback in its registered redirect URIs, matching the --callback-port value.

Claude Desktop

Open Settings → Connectors → Add custom connector and paste the endpoint URL. Org members approve access in the browser and choose the connector. External clients enter their minted client ID and secret under Advanced. Claude Desktop completes the OAuth authorization-code flow in the browser and discovers the channel’s permitted tools.

ChatGPT

ChatGPT's custom connectors speak the same MCP-over-HTTP-with-OAuth shape and work in principle. Claude Desktop and Claude Code are the primary v1 target; treat ChatGPT support as best-effort until it is validated end to end.

Agent sessions and workflow attribution

An agent conversation opened through send_message is pinned to its credential. One end client can never resume another's conversation, even on the same channel. Conversations appear in the dashboard session views with the credential's display name.

A direct workflow call creates a workflow execution attributed to the credential and returns an execution_id. Use get_execution to read that run. It does not create or require an agent conversation.

Access, audit, and rate limits

A credential reaches channels that reference its connector. Direct workflow tools additionally require explicit matched workflow grants. Fabric rechecks the live credential and its attributes when authorizing execution. Revocation prevents new calls; it does not cancel an already-running workflow. Agent-only channels retain their legacy full-agent capability, and agent turns use the existing channel pipeline. Direct workflows execute as the credential principal.

Every brokered turn produces execution events and traces through the same agent session pipeline as any other channel. The end-client credential's ID and display name are stamped onto the session and its spans. Message bodies never appear in audit events. Workflow starts share the per-credential rate limit and check organization execution credits. The rate limit is per server replica; status reads do not consume starts. Per-credential rate limits apply; a client that exceeds its limit gets a structured over-limit error instead of unbounded turns.

Validation

swirls doctor validates block shape and references. It never contacts Swirls Cloud, provisions an OAuth application, or mints a credential.

CheckSeverity
Connector block name does not match ^[a-zA-Z0-9_]+$Error
Duplicate connector block name, in one file or across the projectError
platform: mcp channel missing connector:Error
connector: does not resolve to a declared connector blockError
platform: mcp channel declares connection:Error
platform: mcp channel declares mode:Error
Non-mcp channel declares connector:Error
MCP channel has neither an agent nor a nonempty workflow listError
Non-MCP channel declares workflows:Error
Published workflow is missing, repeated, or named send_message / get_executionError
Published workflow lacks a description or root object inputSchemaError
Direct workflow grant references an undeclared workflowError
Direct workflow grant uses a wildcard or nested bodyError

Common mistakes

Authenticating successfully but seeing no workflow tools

Authentication identifies the credential and its connector. Discovery also checks the channel's published workflow list, the credential's trusted attributes, and matching direct workflow grants. Check all three. An allow ... -> agent ... grant does not grant a direct workflow tool, and credentials created through consent start without attributes.

connector vs connection

The two keywords are one letter apart and point in opposite directions. connector is inbound: external clients authenticate against it to reach your published capabilities. connection is outbound: your workflow or channel authenticates to a third party through it. A platform: mcp channel always uses connector:, never connection:.

// Incorrect: platform: mcp does not take connection:
channel bad {
  platform: mcp
  agent: finance_guy
  connection: client_portal
}
// Correct
channel good {
  platform: mcp
  agent: finance_guy
  connector: client_portal
}

Setting mode: on an MCP channel

mode routes chat-platform events (mention, dm, all) and is meaningless for MCP. Declaring it on a platform: mcp channel is a validation error.

connector: on a non-MCP channel

connector: is only valid on platform: mcp channels. Setting it on slack, linear, discord, or web is a validation error; those platforms use connection:.

Expecting doctor to catch a bad credential

Doctor validates the DSL only: block shape and the channel-to-connector reference. It does not provision the OAuth application, mint a credential, or check whether one exists. A missing or revoked credential shows up as an auth failure when the client connects, not at doctor time. Check the Connectors page in Swirls Cloud when a client reports it cannot authenticate.

Expecting the external client to see the agent's tools

The agent's workflow tools, skills, and mcp: slots are not automatically exposed. send_message runs the agent's turn. To expose a workflow as a separate tool, add it to the channel's workflows list and grant direct access through a policy.

connector vs connection vs mcp block

Three primitives share MCP and OAuth vocabulary and point in different directions.

PrimitiveDirectionWhat it isReferenced by
connector <name> { }InboundSwirls-managed OAuth application external MCP clients authenticate against to reach published agents and workflowschannel.connector: on platform: mcp channels
connection <name> { }OutboundSwirls-brokered OAuth slot to a third-party SaaS (Slack, Linear, Discord, LinkedIn, Microsoft)http nodes, integration nodes, and non-MCP channels, via connection:
mcp <name> { }OutboundRemote MCP server slot your agent consumes tools from (url: in DSL; optional token in Cloud)agent.mcp:

connector authenticates external clients to your published agents and workflows. connection and mcp reach out from your backend to third parties.

Further reading

  • Channels: The channel block, platforms, and routing for Slack, Linear, Discord, and web.
  • MCP servers: The outbound counterpart. Give an agent tools from a remote MCP server.
  • Agents: The agent block, team:, and how a turn runs.
  • Connections: The connection block, for outbound OAuth to a third party.

On this page