This library contains ready-to-import workflow automations that leverage the People.ai MCP (Model Context Protocol) integration alongside AI models, CRM data, and communication tools to deliver actionable sales intelligence.
Each workflow is a complete automation that can be imported into your preferred platform. Workflows combine People.ai's engagement data with Claude AI to generate insights like daily sales digests, meeting briefs, pipeline coaching reports, and account risk alerts.
Supported Platforms:
Any (JSON import)
Workato — Coming Soon
Zapier — Coming Soon
Others — Coming Soon
How it works:
1. Browse the library and pick a workflow
2. Download the workflow JSON
3. Import into your automation platform
4. Connect your credentials (People.ai MCP, Anthropic, Slack, etc.)
5. Configure schedule and channel settings
6. Activate the workflow
Prerequisites:
• An automation platform instance (self-hosted or Cloud)
• People.ai MCP credentials
• Anthropic API key for Claude AI
• Slack Bot token (for most workflows)
• Additional credentials as noted per workflow
Maintained by: AI Innovation Team
Slack: #automation-workflows
Step-by-step configuration guides for the services that power these workflows.
The People.ai Model Context Protocol (MCP) server is the core data source for every workflow in this library. It provides AI agents with direct access to account activity, engagement data, opportunity status, and contact intelligence.
The People.ai MCP server exposes these tools to connected agents:
| Tool | Description | Used By |
|---|---|---|
find_account |
Search for accounts by name or domain | All workflows |
get_account_status |
Account health, engagement score, risk signals | Silence Monitor, Churn Risk |
get_recent_account_activity |
Meetings, emails, calls in a time window | Sales Digest, Channel Pulse |
get_opportunity_status |
Deal stage, amount, close date, activity | Forecast Coach, Deal Hygiene |
get_recent_opportunity_activity |
Recent deal-level interactions and changes | Opportunity Discovery, Win/Loss |
get_engaged_people |
Contacts with recent engagement on an account | Meeting Brief, Sponsor Tracker |
get_scorecard |
Rep and team performance metrics | Activity Gap, Forecast Coach |
ask_sales_ai_about_account |
Natural language queries about any account (10-30s response) | Executive Inbox, QBR Prep |
ask_sales_ai_about_opportunity |
Natural language queries about any deal (10-30s response) | Forecast Coach, Competitive Alert |
top_records |
Top accounts/opps by activity, risk, or value | Territory Heat Map |
account_company_news |
Recent news about an account's company | Meeting Brief, QBR Prep |
Yl1JnBI...)2rT0SWrgR...)n8n v1.19.0+ has a built-in MCP Client tool. Here's the exact configuration:
| Connection Name | People.ai MCP Multi-Header |
| Server URL | https://mcp.people.ai/mcp |
| Authentication | Multiple Headers Auth |
| Header | Name | Value |
|---|---|---|
| Header 1 | PAI-Client-Id |
[Your Client ID] |
| Header 2 | PAI-Client-Secret |
[Your Client Secret] |
| Header 3 | Content-Type |
application/json |
mcp.people.aiPAI-Client-Id (not PAI-Client-ID or pai-client-id).
full.json), the MCP Client Tool node is already configured — just add your credentials.
Add a system prompt to your AI Agent that instructs it how to use People.ai tools:
You are a sales intelligence assistant with access to People.ai CRM data. When users ask about accounts, opportunities, or customer activity: 1) Use People.ai MCP tools to search and retrieve data 2) Analyze the information and provide strategic insights 3) Highlight risks, next steps, and key topics 4) Format responses clearly and actionably
pip install langchain-mcp-adapters
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"peopleai": {
"url": "https://mcp.people.ai/mcp",
"transport": "sse",
"headers": {
"PAI-Client-Id": os.environ["PEOPLEAI_CLIENT_ID"],
"PAI-Client-Secret": os.environ["PEOPLEAI_CLIENT_SECRET"],
"Content-Type": "application/json",
}
}
})
tools = await client.get_tools()
# Bind tools to your LLM: llm.bind_tools(tools)
pip install claude-agent-sdk anthropic
from claude_agent_sdk import Agent
import anthropic
agent = Agent(
client=anthropic.Anthropic(),
model="claude-sonnet-4-20250514",
system="You are a sales intelligence assistant...",
tools=[...], # local tools
mcp_servers=[{
"name": "peopleai",
"url": "https://mcp.people.ai/mcp",
"headers": {
"PAI-Client-Id": os.environ["PEOPLEAI_CLIENT_ID"],
"PAI-Client-Secret": os.environ["PEOPLEAI_CLIENT_SECRET"],
"Content-Type": "application/json",
}
}],
)
pip install openai-agents
from agents import Agent
from agents.mcp import MCPServerSse
peopleai_mcp = MCPServerSse(
name="peopleai",
url="https://mcp.people.ai/mcp",
headers={
"PAI-Client-Id": os.environ["PEOPLEAI_CLIENT_ID"],
"PAI-Client-Secret": os.environ["PEOPLEAI_CLIENT_SECRET"],
"Content-Type": "application/json",
},
)
agent = Agent(
name="Sales Intelligence",
instructions="You are a sales intelligence assistant...",
tools=[...], # local tools
mcp_servers=[peopleai_mcp],
)
Set these for Python-based workflows (LangGraph, Claude Agent, OpenAI Agent):
export PEOPLEAI_MCP_URL="https://mcp.people.ai/mcp" export PEOPLEAI_CLIENT_ID="your-client-id" export PEOPLEAI_CLIENT_SECRET="your-client-secret" # Also needed for the LLM: export ANTHROPIC_API_KEY="sk-ant-..." # for Claude Agent / LangGraph (recommended) export OPENAI_API_KEY="sk-..." # for OpenAI Agent
Try these example queries in n8n or your agent to verify the connection:
"Find the account for [Company Name]""What are the risks for opportunity [ID]?""Show me recent activity for [Account Name]"Check the execution log to verify: MCP tools appear in available tools, AI Agent calls them successfully, and data is returned.
| Issue | Cause | Fix |
|---|---|---|
| Can't find MCP Client tool | n8n version below 1.19.0 | Update n8n to v1.19.0 or later |
| Connection failed / server not responding | Wrong URL or network issue | Verify URL is exactly https://mcp.people.ai/mcp (no trailing slash). Check firewall/proxy settings for self-hosted n8n. |
| Authentication failed | Wrong credentials or header names | Header names are case-sensitive: PAI-Client-Id, PAI-Client-Secret. Verify MCP-specific credentials (not REST API keys). Check for extra spaces. |
| AI Agent not using People.ai tools | Prompt too vague or MCP tool not connected | Be explicit in prompts: "Use the find_account tool to search for [company]." Verify MCP Client is connected to the AI Agent node. |
| Workflow times out | AI-powered tools (ask_sales_ai_*) take 10-30s |
Increase workflow timeout. Use simpler tools like get_account_status for faster responses. |
| Tool returns empty data | Account name mismatch or no activity | Use exact account names from Salesforce; widen the lookback window |
For best results, use the People.ai Insights Export REST API for bulk data extraction and MCP tools for deep intelligence on specific items. Example pattern:
This hybrid approach combines the efficiency of bulk APIs with the intelligence of AI-powered analysis.
Most workflows in this library deliver results via Slack. Follow these steps to create and configure a Slack bot with the right permissions.
Automation Catalog Bot) and select your workspaceNavigate to OAuth & Permissions in the sidebar, scroll to Bot Token Scopes, and add:
| Scope | Purpose | Required By |
|---|---|---|
chat:write |
Send messages to channels and DMs | All workflows |
chat:write.customize |
Send messages with custom bot name/icon | All workflows |
channels:read |
List public channels | Channel-targeted workflows |
groups:read |
List private channels the bot is in | Private channel delivery |
im:write |
Open and send direct messages | DM-based workflows (Sales Digest, Meeting Brief) |
users:read |
Look up user IDs by name/email | Subscriber-based workflows |
users:read.email |
Look up users by email address | Email-to-Slack user mapping |
files:write |
Upload files and snippets | Workflows with file attachments (QBR Prep) |
reactions:write |
Add emoji reactions to messages | Optional — status indicators |
xoxb-)The bot can only post to channels it's been invited to:
/invite @Automation Catalog Bot (or your bot's name)im:writexoxb- token in the Access Token fieldexport SLACK_BOT_TOKEN="xoxb-your-token-here"
To customize how the bot appears in Slack:
chat:write.customize scope| Error | Cause | Fix |
|---|---|---|
not_in_channel |
Bot hasn't been invited to the channel | /invite @BotName in the channel |
channel_not_found |
Wrong channel ID or channel is private | Use channel ID (not name) — find it in channel details |
missing_scope |
Required scope not added | Add the scope, then reinstall the app to workspace |
invalid_auth |
Token is wrong, expired, or revoked | Reinstall app and copy the new token |
ratelimited |
Too many API calls | Add delays between messages; Slack allows ~1 msg/sec per channel |
xoxb- token to source control.
Store it as an environment variable or in your platform's credential store.
Rotate tokens immediately if exposed.
Workflows in this library can deliver results to Microsoft Teams via two methods: Incoming Webhooks (quick setup, channel-only) or a Bot Framework bot (full-featured, supports DMs and adaptive cards).
Fastest way to post messages to a Teams channel. No Azure registration needed.
Automation Catalog) and optionally upload an iconhttps://outlook.office.com/webhook/...POST a JSON payload to the webhook URL. Teams supports two formats:
POST {webhook_url}
Content-Type: application/json
{
"@type": "MessageCard",
"summary": "Silence Alert",
"themeColor": "FF6B6B",
"title": "🔴 SILENCE ALERT — 3 accounts need attention",
"text": "**Globex Industries** — 18 days silent..."
}
POST {webhook_url}
Content-Type: application/json
{
"type": "message",
"attachments": [{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{ "type": "TextBlock", "text": "Sales Digest", "weight": "Bolder", "size": "Large" },
{ "type": "TextBlock", "text": "Your daily summary...", "wrap": true }
]
}
}]
}
import os, json
from urllib.request import Request, urlopen
webhook_url = os.environ["TEAMS_WEBHOOK_URL"]
payload = json.dumps({
"@type": "MessageCard",
"summary": "Alert",
"title": "🔴 Silence Alert",
"text": message_content,
}).encode()
req = Request(webhook_url, data=payload,
headers={"Content-Type": "application/json"})
urlopen(req)
Full-featured bot with DM support, adaptive cards, and proactive messaging. Required for workflows that deliver personalized content to individual users.
Automation Catalog BotIn your app registration, go to API permissions → Add a permission → Microsoft Graph:
| Permission | Type | Purpose |
|---|---|---|
ChatMessage.Send |
Application | Send messages to chats and channels |
Chat.Create |
Application | Create 1:1 chats for DM delivery |
Chat.ReadWrite.All |
Application | Read/write to chats (proactive messaging) |
User.Read.All |
Application | Look up users by email for DM targeting |
ChannelMessage.Send |
Application | Post to specific team channels |
Team.ReadBasic.All |
Application | List teams and channels |
Click Grant admin consent after adding permissions (requires admin role).
export TEAMS_TENANT_ID="your-tenant-id"
export TEAMS_CLIENT_ID="your-client-id"
export TEAMS_CLIENT_SECRET="your-client-secret"
# Python example — send via Graph API
import msal, requests
app = msal.ConfidentialClientApplication(
os.environ["TEAMS_CLIENT_ID"],
authority=f"https://login.microsoftonline.com/{os.environ['TEAMS_TENANT_ID']}",
client_credential=os.environ["TEAMS_CLIENT_SECRET"],
)
token = app.acquire_token_for_client(
scopes=["https://graph.microsoft.com/.default"]
)
requests.post(
f"https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages",
headers={"Authorization": f"Bearer {token['access_token']}"},
json={"body": {"content": message_content}},
)
| Error | Cause | Fix |
|---|---|---|
403 Forbidden |
Missing admin consent on Graph permissions | Azure Portal → API permissions → Grant admin consent |
404 Not Found |
Wrong team/channel ID or bot not installed | Verify IDs via Graph Explorer; ensure bot is added to the team |
InvalidAuthenticationToken |
Expired or malformed token | Re-acquire token via MSAL; check client secret expiry |
Webhook returns 400 |
Malformed JSON payload | Validate against Adaptive Cards Designer |
| Messages not appearing | Webhook URL expired or connector removed | Recreate the Incoming Webhook connector in the channel |
Throttled (429) |
Rate limit exceeded | Graph API allows ~30 msgs/sec per app; add retry with backoff |
Workflows can deliver results to Google Chat via Incoming Webhooks (quick, space-only) or a Google Chat App (DM support, cards, slash commands).
Automation Catalog) and optionally set an avatar URLhttps://chat.googleapis.com/v1/spaces/.../messages?key=...&token=...POST {webhook_url}
Content-Type: application/json
{
"text": "🔴 *SILENCE ALERT* — 3 accounts need attention\n\n*Globex Industries* — 18 days silent..."
}
POST {webhook_url}
Content-Type: application/json
{
"cardsV2": [{
"cardId": "silence-alert",
"card": {
"header": {
"title": "Silence Alert",
"subtitle": "3 accounts need attention",
"imageUrl": "https://example.com/icon.png"
},
"sections": [{
"header": "🔴 Critical",
"widgets": [{
"decoratedText": {
"topLabel": "Globex Industries — $340,000",
"text": "18 days silent (normally 3-day cadence)"
}
}]
}]
}
}]
}
text or cardsV2 payloadimport os, json
from urllib.request import Request, urlopen
webhook_url = os.environ["GOOGLE_CHAT_WEBHOOK_URL"]
payload = json.dumps({"text": message_content}).encode()
req = Request(webhook_url, data=payload,
headers={"Content-Type": "application/json"})
urlopen(req)
Full-featured app with DM support, interactive cards, and slash commands. Required for personalized delivery to individual users.
automation-catalog-bot)To send DMs without user interaction (proactive messaging), you need a service account:
chat-bot-sender| Scope | Purpose |
|---|---|
https://www.googleapis.com/auth/chat.bot |
Send and manage messages as the Chat app |
https://www.googleapis.com/auth/chat.spaces |
List and manage spaces the app belongs to |
https://www.googleapis.com/auth/chat.messages.create |
Create messages in spaces and DMs |
https://www.googleapis.com/auth/chat.memberships |
Look up space members for DM targeting |
from google.oauth2 import service_account
from googleapiclient.discovery import build
creds = service_account.Credentials.from_service_account_file(
os.environ["GOOGLE_CHAT_SA_KEY"],
scopes=["https://www.googleapis.com/auth/chat.bot"],
)
chat = build("chat", "v1", credentials=creds)
# Create or find DM space with user
dm = chat.spaces().setup(body={
"space": {"spaceType": "DIRECT_MESSAGE"},
"memberships": [{"member": {"name": f"users/{user_email}", "type": "HUMAN"}}],
}).execute()
# Send message
chat.spaces().messages().create(
parent=dm["name"],
body={"text": digest_content},
).execute()
| Error | Cause | Fix |
|---|---|---|
403 PERMISSION_DENIED |
Chat API not enabled or missing scopes | Enable Chat API; verify service account scopes |
404 NOT_FOUND |
Space doesn't exist or app not added | Add the Chat app to the space first |
FAILED_PRECONDITION |
App can't DM users who haven't interacted with it | User must message the app first, or use spaces().setup() with domain-wide delegation |
Webhook returns 400 |
Invalid JSON or card schema | Validate with Card Builder |
| Rate limited | Exceeding Chat API quotas | Default: 60 msgs/min per space; add batching with delays |
Email is the universal fallback — every workflow can deliver via SMTP. This guide covers Gmail, Outlook/M365, SendGrid, and generic SMTP.
Google blocks "less secure app" logins. Use an App Password instead:
Automation Catalog)| Host | smtp.gmail.com |
| Port | 587 (STARTTLS) or 465 (SSL) |
| Username | Your full Gmail address |
| Password | The 16-character App Password (not your Google password) |
| Daily limit | 500 emails (personal) / 2,000 (Workspace) |
For Google Workspace orgs, the Gmail API with a service account avoids App Passwords:
https://www.googleapis.com/auth/gmail.send scope| Host | smtp.office365.com |
| Port | 587 (STARTTLS) |
| Username | Your full email address |
| Password | Account password (or App Password if MFA enabled) |
| Auth | SMTP AUTH must be enabled per-mailbox by M365 admin |
M365 disables SMTP AUTH by default. An admin must enable it:
For production use, the Graph API with app-only auth is more reliable:
POST https://graph.microsoft.com/v1.0/users/{sender}/sendMail
Authorization: Bearer {token}
{
"message": {
"subject": "Weekly Forecast Coaching",
"body": { "contentType": "HTML", "content": "<h1>Report...</h1>" },
"toRecipients": [{ "emailAddress": { "address": "leader@company.com" } }]
}
}
Requires the Mail.Send application permission with admin consent.
Best for production — high deliverability, no per-user mailbox needed, generous free tier (100 emails/day).
SG.)| Host | smtp.sendgrid.net |
| Port | 587 (STARTTLS) or 465 (SSL) |
| Username | apikey (literally the word "apikey") |
| Password | Your SendGrid API key |
POST https://api.sendgrid.com/v3/mail/send
Authorization: Bearer SG.your-api-key
Content-Type: application/json
{
"personalizations": [{"to": [{"email": "leader@company.com"}]}],
"from": {"email": "automation@company.com", "name": "Automation Catalog"},
"subject": "Weekly Forecast Coaching",
"content": [{"type": "text/html", "value": "<h1>Report</h1>"}]
}
export SMTP_HOST="smtp.gmail.com" # or smtp.office365.com, smtp.sendgrid.net
export SMTP_PORT="587"
export SMTP_USER="you@company.com" # or "apikey" for SendGrid
export SMTP_PASS="your-app-password" # or API key for SendGrid
# Python example
import os, smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
msg = MIMEMultipart("alternative")
msg["Subject"] = "Weekly Forecast Coaching"
msg["From"] = os.environ["SMTP_USER"]
msg["To"] = "leader@company.com"
msg.attach(MIMEText(plain_text, "plain"))
msg.attach(MIMEText(html_content, "html"))
with smtplib.SMTP(os.environ["SMTP_HOST"], int(os.environ["SMTP_PORT"])) as s:
s.starttls()
s.login(os.environ["SMTP_USER"], os.environ["SMTP_PASS"])
s.send_message(msg)
| Provider | Free Tier | Best For | Setup |
|---|---|---|---|
| Gmail | 500/day | Prototyping, small teams | 5 min |
| Outlook / M365 | 10,000/day | Microsoft shops | 10 min (+ admin) |
| SendGrid | 100/day | Production, high deliverability | 15 min |
| Amazon SES | 62,000/mo (from EC2) | AWS-native orgs, volume | 30 min |
| Error | Cause | Fix |
|---|---|---|
535 Authentication failed |
Wrong password or App Password needed | Use App Password (Gmail) or enable SMTP AUTH (M365) |
Connection refused (port 25) |
ISP or cloud provider blocks port 25 | Use port 587 (STARTTLS) or 465 (SSL) instead |
| Emails going to spam | Missing SPF/DKIM/DMARC records | Set up domain authentication with your email provider |
Daily sending limit reached |
Exceeded provider quota | Upgrade plan or switch to SendGrid/SES for volume |
| HTML not rendering | Sent as plain text instead of HTML | Set content type to text/html or use multipart/alternative |