AI Agent Integration
Connect AI agents to the Loop comms platform via the Model Context Protocol (MCP). The @loop/mcp-comms server exposes 59 tools for managing content, audiences, sends, analytics, and more.
MCP Transport Setup
The MCP server supports two transport modes: stdio for local development and HTTP/SSE for remote agents.
stdio Transport (Local)
Run the MCP server as a subprocess from your AI agent:
{
"mcpServers": {
"loop-comms": {
"command": "npx",
"args": ["@loop/mcp-comms"],
"env": {
"LOOP_API_KEY": "lk_dev_...",
"LOOP_BRAND_ID": "your-brand-uuid"
}
}
}
}For Cursor or Claude Desktop, add this to your MCP configuration file.
HTTP/SSE Transport (Remote)
For hosted agents, connect to the SSE endpoint:
SSE endpoint: https://comms.loop.health/mcp/sse
Message endpoint: https://comms.loop.health/mcp/messageExample connection with the MCP SDK:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
const transport = new SSEClientTransport(
new URL('https://comms.loop.health/mcp/sse'),
{
requestInit: {
headers: {
'Authorization': 'Bearer <OAUTH_TOKEN>',
},
},
}
);
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);Clerk OAuth Authentication
The MCP server authenticates via Clerk OAuth. AI agents need a valid OAuth token to connect.
OAuth Flow
- Register your agent as an OAuth application in Clerk
- Request a token with the
comms:toolsscope - Include the token in the
Authorizationheader
POST https://clerk.loop.health/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=your_client_id
&client_secret=your_client_secret
&scope=comms:toolsService Tokens
For automated agents running without user context, use a service token:
LOOP_SERVICE_TOKEN=lst_...Service tokens are scoped to a specific brand and role.
Role Mapping
The MCP server enforces RBAC on every tool call. The authenticated user’s role determines which tools are available.
| Role | Access Level |
|---|---|
admin | All 59 tools |
marketing | Content, audiences, sequences, sends, pages, shares, reports, analytics |
advisor | Content (read), sends (draft/preview), analytics |
ops | Ops tools, audit, platform health, flags |
educator | Content (read), pages (read), shares (read) |
Role is determined from Clerk publicMetadata.adminRole. If no role is set, all tool calls are denied.
Role Constants
const ALL_ROLES = ['admin', 'marketing', 'advisor', 'ops', 'educator'];
const ADMIN_ONLY = ['admin'];
const MARKETING_AND_ADMIN = ['admin', 'marketing'];
const OPS_AND_ADMIN = ['admin', 'ops'];Tool Discovery
After connecting, list available tools to see what’s accessible for the current role:
const { tools } = await client.listTools();
for (const tool of tools) {
console.log(`${tool.name}: ${tool.description}`);
}The server returns only the tools the authenticated role can access. An admin sees all 59 tools; a marketing user sees a filtered subset.
Tool Categories
| Category | Tool Count | Example Tools |
|---|---|---|
| Content | 8 | templates.list, templates.create, voice.get |
| Audiences | 4 | audiences.create_from_description, audiences.preview |
| Sequences | 5 | sequences.create, sequences.simulate |
| Sends | 5 | sends.draft, sends.schedule |
| Pages | 6 | pages.draft, pages.publish |
| Shares | 8 | share.draft, share.publish |
| Transactional | 5 | events.declare, events.fire_test |
| Reports | 3 | reports.create, reports.schedule_send |
| Routing | 3 | routing.propose_rule, routing.simulate |
| Analytics | 2 | analytics.ask, anomaly.explain |
| Ops | 6 | brands.list, audit.search, platform.health |
| SQL | 1 | sql.run |
| State | 1 | state.recent_changes |
| Pairing | 2 | session.pair, session.disconnect |
Example Session
Here’s a complete session where an AI agent creates and sends a marketing email:
Agent → server: tools/list
Server → agent: [59 tools listed]
Agent → server: tools/call
tool: templates.list
input: { "channel": "email", "status": "active" }
Server → agent: [3 templates returned]
Agent → server: tools/call
tool: audiences.create_from_description
input: {
"description": "Customers who purchased BPC-157 in the last 30 days",
"brandId": "brand-uuid"
}
Server → agent: { "audienceId": "aud_abc123", "estimatedSize": 1247 }
Agent → server: tools/call
tool: sends.draft
input: {
"templateId": "tpl_xyz789",
"audienceId": "aud_abc123",
"subject": "Your BPC-157 protocol update"
}
Server → agent: { "sendId": "snd_def456", "status": "draft", "estimatedRecipients": 1247 }
Agent → server: tools/call
tool: sends.preview
input: { "sendId": "snd_def456" }
Server → agent: { "previewUrl": "https://comms.loop.health/preview/snd_def456", "html": "..." }
Agent → server: tools/call
tool: sends.schedule
input: { "sendId": "snd_def456", "scheduledAt": "2026-05-20T10:00:00Z" }
Server → agent: { "sendId": "snd_def456", "status": "scheduled", "scheduledAt": "2026-05-20T10:00:00Z" }Next Steps
- MCP Tool Catalog — Complete reference for all 59 tools
- Tutorials — Step-by-step guides using MCP tools
- Event Catalog — Event schemas for transactional messaging