SWIRLS_
Agents

MCP channels

Expose a deployed agent as a remote MCP server that Claude Desktop, Claude Code, and ChatGPT connect to as a custom connector.

What it is. A platform: mcp channel exposes one deployed agent as a remote MCP server. External clients connect to it as a custom connector and talk to the agent directly, from a tool they already use.

Use it when a client needs direct access to an agent from Claude Desktop, Claude Code, or ChatGPT, and logging into Swirls Cloud is the wrong ask. This is the delivery model for MSPs and FDEs handing clients agents they built on Swirls.

Works with agents (the actor exposed), channels (mcp is a channel platform, sibling to slack/linear/discord/web), and a top-level connector block (the inbound OAuth application).

MCP channels are the inverse of MCP servers. An mcp block gives your agent tools from an external server: your agent acts as an MCP client. A platform: mcp channel gives an external client access to your agent: your agent acts as an MCP server. Same protocol, opposite direction.

The connector block

A connector block declares a Swirls-managed inbound OAuth application: the application external MCP clients authenticate against to reach your agents. 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 an agent you own. See connector vs connection vs mcp block below.

The channel block: platform: mcp

A platform: mcp channel binds one agent to one connector, and becomes one MCP endpoint.

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.
agentidentifierYesName of the top-level agent block this endpoint exposes.
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 agents

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 agent.

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 grants exactly the channels that reference it, so this client sees both finance and product as separate connectors in its tool.

Enabled platform: mcp channels are unique per agent, the same routing rule non-web channels use elsewhere: two enabled channels cannot share the same platform : mode : agent tuple, and mode is fixed for MCP. In practice this means one agent gets one MCP endpoint. To put the same agent behind two different connectors, disable one of the channels first.

Two delivery shapes fall out of the same primitive:

  • 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
}

Chat brokering, not tool projection

The MCP tool surface a client sees is a send_message-style tool, not the agent's own tools. Calling it starts or resumes a conversation with the agent and returns its reply, the same turn pipeline Portal chat and Slack use. The agent's workflow tools, skills, and any mcp: slots it consumes stay behind the turn. The external client never sees them directly; it only ever talks to the agent, which decides what to do with its own tools.

Deploy, then mint a credential

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.

  1. 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.
  2. On the project Connectors page in Swirls Cloud, mint a named credential for the end client, for example "Acme Corp". The page returns a client ID and a client secret.
  3. 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.
  4. 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.

Credentials are per end client and 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

Give the end client this URL plus the client ID and secret you minted for them.

Claude Desktop

Open Settings → Connectors → Add custom connector, paste the endpoint URL, and enter the client ID and client secret. Claude Desktop completes the OAuth authorization-code flow in the browser and lists the channel's agent as a connector.

Claude Code

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

Claude Code opens a browser to complete the OAuth flow against the credential you minted.

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.

Sessions and attribution

Every MCP session is pinned to the credential that opened it. One end client can never resume another's session, even on the same channel. Session rows surface in the existing Portal session views, labeled with the credential's display name, so you can see which client talked to which agent.

Access, audit, and rate limits

Any credential holder gets the bound agent's full capability. There is no separate MCP grant dimension: the credential-to-channel scope is the boundary, and a credential grants exactly the channels whose connector: names its application.

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. 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

Common mistakes

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 agent. 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 MCP tool surface is send_message, not the agent's workflow tools, skills, or mcp: slots. Projecting an agent's own tools as individual MCP tools is not supported: the agent loop stays the orchestrator, and the external client only ever talks to the agent.

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; exposes your agents as remote MCP serverschannel.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, bound to a URL in Swirls Cloudagent.mcp:

connector exposes your agents to external clients. connection and mcp reach out from your agents 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