MCP Examples

Real-world workflows combining AI steps with MCP tool calls.

CRM Lead Enrichment

Enrich incoming leads with company data and create follow-up tasks:

1import { relay } from '@relayplane/sdk'
2
3relay.configure({
4 providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } },
5 mcp: {
6 servers: {
7 crm: { url: 'https://mcp.salesforce.com' },
8 clearbit: { url: 'https://mcp.clearbit.com' }
9 }
10 }
11})
12
13const leadEnrichment = relay
14 .workflow('lead-enrichment')
15 // Extract company domain from email
16 .step('extractDomain')
17 .with('openai:gpt-4o')
18 .prompt('Extract the company domain from this email address: {{input.email}}. Return just the domain.')
19 // Look up company in Clearbit
20 .step('enrichCompany')
21 .mcp('clearbit:getCompanyByDomain')
22 .params({ domain: '{{extractDomain.output}}' })
23 .depends('extractDomain')
24 // Score the lead based on enriched data
25 .step('scoreLead')
26 .with('openai:gpt-4o')
27 .depends('enrichCompany')
28 .prompt(`Based on this company data, score this lead from 1-100:
29 Company: {{enrichCompany.name}}
30 Industry: {{enrichCompany.industry}}
31 Employees: {{enrichCompany.employees}}
32 Revenue: {{enrichCompany.estimatedRevenue}}
33
34 Return a JSON object: { "score": number, "reasoning": string }`)
35 // Create or update CRM record
36 .step('updateCRM')
37 .mcp('crm:upsertLead')
38 .params({
39 email: '{{input.email}}',
40 company: '{{enrichCompany.name}}',
41 industry: '{{enrichCompany.industry}}',
42 leadScore: '{{scoreLead.score}}'
43 })
44 .depends('scoreLead')
45
46const result = await leadEnrichment.run({
47 email: 'john.smith@acme.com'
48})

GitHub Issue Triage

Automatically analyze and triage GitHub issues:

1import { relay } from '@relayplane/sdk'
2
3relay.configure({
4 providers: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } },
5 mcp: {
6 servers: {
7 github: {
8 url: 'https://mcp.github.com',
9 credentials: { token: process.env.GITHUB_TOKEN }
10 }
11 }
12 }
13})
14
15const issueTriage = relay
16 .workflow('issue-triage')
17 // Get issue details
18 .step('getIssue')
19 .mcp('github:getIssue')
20 .params({
21 owner: '{{input.owner}}',
22 repo: '{{input.repo}}',
23 issueNumber: '{{input.issueNumber}}'
24 })
25 // Analyze the issue
26 .step('analyze')
27 .with('anthropic:claude-sonnet-4-20250514')
28 .depends('getIssue')
29 .prompt(`Analyze this GitHub issue and provide:
30 1. Category (bug, feature, question, docs)
31 2. Priority (P0, P1, P2, P3)
32 3. Suggested labels
33 4. Brief summary
34
35 Issue Title: {{getIssue.title}}
36 Issue Body: {{getIssue.body}}
37
38 Return JSON: { "category": string, "priority": string, "labels": string[], "summary": string }`)
39 // Apply labels
40 .step('addLabels')
41 .mcp('github:addLabels')
42 .params({
43 owner: '{{input.owner}}',
44 repo: '{{input.repo}}',
45 issueNumber: '{{input.issueNumber}}',
46 labels: '{{analyze.labels}}'
47 })
48 .depends('analyze')
49 // Add comment with analysis
50 .step('addComment')
51 .mcp('github:createComment')
52 .params({
53 owner: '{{input.owner}}',
54 repo: '{{input.repo}}',
55 issueNumber: '{{input.issueNumber}}',
56 body: `## Automated Triage
57
58**Category:** {{analyze.category}}
59**Priority:** {{analyze.priority}}
60**Summary:** {{analyze.summary}}`
61 })
62 .depends('analyze')
63
64const result = await issueTriage.run({
65 owner: 'myorg',
66 repo: 'myproject',
67 issueNumber: 123
68})

Smart Slack Notifications

Route alerts to the right channel with AI-powered classification:

1import { relay } from '@relayplane/sdk'
2
3relay.configure({
4 providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } },
5 mcp: {
6 servers: {
7 slack: {
8 url: 'https://mcp.slack.com',
9 credentials: { token: process.env.SLACK_BOT_TOKEN }
10 }
11 }
12 }
13})
14
15const alertRouter = relay
16 .workflow('alert-router')
17 // Classify the alert
18 .step('classify')
19 .with('openai:gpt-4o')
20 .prompt(`Classify this alert and determine the appropriate Slack channel:
21
22 Alert: {{input.alertMessage}}
23 Severity: {{input.severity}}
24
25 Available channels:
26 - #incidents - Critical production issues
27 - #security - Security-related alerts
28 - #platform - Infrastructure and platform issues
29 - #general-alerts - Everything else
30
31 Return JSON: { "channel": string, "urgency": "high" | "medium" | "low", "summary": string }`)
32 // Send to appropriate channel
33 .step('notify')
34 .mcp('slack:postMessage')
35 .params({
36 channel: '{{classify.channel}}',
37 text: '{{classify.urgency === "high" ? " " : ""}}*{{input.severity}} Alert*\n{{classify.summary}}'
38 })
39 .depends('classify')
40
41const result = await alertRouter.run({
42 alertMessage: 'Database connection pool exhausted on prod-db-1',
43 severity: 'CRITICAL'
44})
MCP workflows are great for connecting AI reasoning with real-world actions. Use AI steps to analyze and decide, then MCP steps to execute actions.

Next Steps