Claude-skill-registry affinity-mcp-workflows
Use when working with Affinity CRM via MCP tools - find entities, manage workflows, log interactions, prepare briefings, find warm intros. Also use when user mentions "pipeline", "deals", "relationship strength", or wants to prepare for meetings.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/affinity-mcp-workflows" ~/.claude/skills/majiayu000-claude-skill-registry-affinity-mcp-workflows && rm -rf "$T"
skills/data/affinity-mcp-workflows/SKILL.md- pip install
Affinity MCP Workflows
This skill covers the xaffinity MCP server tools, prompts, and resources for working with Affinity CRM.
Prerequisites
The MCP server requires the xaffinity CLI to be installed:
pip install "affinity-sdk[cli]"
The CLI must be configured with an API key before the MCP server will work.
⚠️ REQUIRED WORKFLOW - Do Not Skip Steps
You MUST complete steps 1-2 before running ANY queries or commands.
Skipping these steps leads to incorrect or inefficient queries because:
- Command syntax may have changed since this skill was written
- New flags (like
) may exist that you don't know about--with-interaction-dates - You may use deprecated syntax that returns incomplete data
- The data model has nuances (e.g.,
vslist export
) that you'll misscompany ls
Mandatory Pre-Flight Checklist
Before proceeding to execute any commands:
- ✅ Read
usingxaffinity://data-modelread-xaffinity-resource - ✅ Run
for your specific taskdiscover-commands - ✅ State what you learned from each step before continuing
Example:
"I read the data-model resource and learned that list entries have custom fields accessed via fields.<Name>. I ran discover-commands for 'interaction' and found that interaction ls supports --type all to fetch all types in one call, and --days to limit the time range. Now I'll proceed with..."
IMPORTANT: Write Operations Only After Explicit User Request
Only use tools or prompts that modify CRM data when the user explicitly asks to do so.
Write operations include:
- Tools:
execute-write-command - Prompts:
,log-interaction-and-update-workflow
,change-status
,log-calllog-message
Read-only operations (search, lookup, briefings) can be used proactively to help the user. But never create, update, or delete CRM records unless the user specifically requests it.
Full Scan Protection
The MCP gateway enforces pagination limits to prevent unbounded data scans:
| Limit | Value | Description |
|---|---|---|
| Default | 1000 records | Applied when no specified |
| Maximum | 10000 records | Higher values are capped with a warning |
flag | BLOCKED | Use or cursor pagination instead |
Affected commands:
list export, list ls, person ls, company ls, opportunity ls, note ls, reminder ls, interaction ls, field history
To fetch more than 10000 records: Use cursor pagination with
--cursor flag.
Available Tools
CLI Gateway (Primary Interface)
The CLI Gateway provides full access to the xaffinity CLI:
| Tool | Use Case |
|---|---|
| Search CLI commands by keyword (e.g., "create person", "export list") |
| Execute read-only CLI commands (get, search, list, export) |
| (write) Execute write CLI commands (create, update, delete) |
Usage pattern:
- Discover the right command:
discover-commands(query: "create person", category: "write") - Execute it:
execute-write-command(command: "person create", argv: ["--first-name", "John", "--last-name", "Doe"])
Utility Tools
| Tool | Use Case |
|---|---|
| Comprehensive entity info (details, relationship strength, interactions, notes, list memberships) |
| Access dynamic resources via URIs |
Destructive Commands
Commands that delete data require double confirmation:
- Look up the entity first using
to show what will be deletedexecute-read-command - Ask the user in your response by showing them the entity details and requesting confirmation
- Wait for user's next message - do NOT proceed until they explicitly confirm
- Only after user confirms should you execute with
confirm: true
Example flow:
User: "Delete person 123" You: execute-read-command(command: "person get", argv: ["123"]) You: "This will permanently delete John Smith (ID: 123, email: john@example.com). Type 'yes' to confirm deletion." [Stop here and wait for user's response] User: "yes" You: execute-write-command(command: "person delete", argv: ["123"], confirm: true)
Query vs CLI Commands: When to Use What
Use
tool for:query
- Any operation needing relationships (persons at a company, companies for a person)
- Any operation needing computed data (interaction dates, unreplied messages)
- Pipeline analysis with aggregations or groupBy
- Complex filtering with AND/OR conditions
- List entry operations that need associated entities
Use individual CLI commands for:
- Simple lookups:
,person get 123company get 456 - Quick searches:
,person ls --query "John"company ls --query "Acme" - Metadata:
,list lsfield ls --list-id <id> - Write operations: All creates, updates, deletes
Query Examples (Preferred for Complex Operations)
⚠️ STOP: Did you complete the pre-flight checklist? The syntax below may be outdated. Run
discover-commands first to verify current syntax and available flags.
⚠️ For queries with
or expand
, ALWAYS use include
first to see estimated API calls. These cause N+1 API calls (one per record) and can be slow or timeout.dryRun: true
// STEP 1: Preview any expand/include query with dryRun first {"query": {"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "expand": ["interactionDates"], "limit": 100}, "dryRun": true} // STEP 2: If API calls look reasonable (<200), run without dryRun {"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "expand": ["interactionDates"], "limit": 100} // Pipeline with field values and unreplied email detection {"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "select": ["entityName", "fields.Status", "fields.Owner"], "expand": ["unreplied"]} // Persons with their companies and interaction history summary {"from": "persons", "where": {"path": "email", "op": "contains", "value": "@acme.com"}, "include": ["companies"], "expand": ["interactionDates"]} // Pipeline summary by status (aggregation) - no expand, no dryRun needed {"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "groupBy": "fields.Status", "aggregate": {"count": {"count": true}}} // List entries with associated persons and interactions (parameterized include) {"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "include": [{"interactions": {"limit": 50, "days": 180}}, "persons"]}
Common CLI Commands
⚠️ Reminder: Run
discover-commands first. The commands below are examples - actual syntax and flags may differ.
Use
discover-commands to find commands, then execute-read-command or execute-write-command to run them.
Search & Lookup (Simple Operations)
| Command | Use Case |
|---|---|
| Quick search persons by name/email |
| Quick search companies |
| List all Affinity lists |
| Get field definitions and dropdown options |
Note: For list exports needing relationships or computed data, use
query instead of list export.
Entity Details
| Command | Use Case |
|---|---|
| Get person details |
| Get company details |
| Get opportunity details |
| Get relationship strength for a person |
| Get all interactions (or use specific type: email, meeting, call, chat-message) |
| Audit who changed a field and when. Use to track status changes or investigate field modifications. Requires exactly one entity selector: , , , or |
Write Operations
| Command | Use Case |
|---|---|
| Log a call/meeting/email |
| Add a note |
| Update a field value |
| Create a person |
MCP Prompts (Guided Workflows)
These prompts provide guided multi-step workflows. Suggest them when appropriate.
Note: Prompts marked with (write) modify CRM data - only use when user explicitly requests.
| Prompt | Type | When to Suggest |
|---|---|---|
| read-only | User has upcoming meeting, needs context on a person/company |
| read-only | User wants weekly/monthly pipeline review |
| read-only | User wants to find introduction path to someone |
| read-only | Get interaction history summary for an entity |
| write | User explicitly asks to log a call/meeting and update pipeline |
| write | User explicitly asks to move a deal to new stage |
| write | User explicitly asks to log a phone call |
| write | User explicitly asks to log a chat/text message |
How to Invoke Prompts
Prompts are invoked with arguments. Example:
prepare-briefing(entityName: "John Smith", meetingType: "demo")warm-intro(targetName: "Jane Doe", context: "partnership discussion")log-interaction-and-update-workflow(personName: "Alice", interactionType: "call", summary: "Discussed pricing")
Resources
Access dynamic data via
xaffinity:// URIs using read-xaffinity-resource:
| URI | Returns |
|---|---|
| Current authenticated user details |
| Current user's person ID in Affinity |
| Valid interaction types and directions |
| Saved views available for a list |
| Field definitions for a list |
| Workflow configuration for a list |
Common Workflow Patterns
⚠️ Before using any pattern below: Complete the pre-flight checklist (read data-model, run discover-commands, state what you learned).
Before a Meeting
- Use
for full context (relationship strength, recent interactions, notes)get-entity-dossier - Or use:
prompt for a guided flowprepare-briefing
After a Call/Meeting
- Use
withexecute-write-command
to log what happenedinteraction create - Use
to find list entry:query{"from": "listEntries", "where": {"and": [{"path": "listName", "op": "eq", "value": "Dealflow"}, {"path": "entityName", "op": "contains", "value": "Acme"}]}} - Use
withexecute-write-command
if deal stage changedentry field - Or use:
promptlog-interaction-and-update-workflow
Finding Warm Introductions
- Use
withexecute-read-command
to locate target personperson ls - Use
withexecute-read-command
for connection strengthrelationship-strength ls - Or use:
prompt for guided flowwarm-intro
Pipeline Review
- Use
with aggregation:query{"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "groupBy": "fields.Status", "aggregate": {"count": {"count": true}}} - Use
with expand for details:query{"from": "listEntries", "where": {"path": "listName", "op": "eq", "value": "Dealflow"}, "expand": ["interactionDates", "unreplied"]} - Or use:
promptpipeline-review
Updating Deal Status
- Use
to find the entry:query{"from": "listEntries", "where": {"and": [{"path": "listName", "op": "eq", "value": "Dealflow"}, {"path": "entityName", "op": "contains", "value": "..."}]}} - Use
withexecute-read-command
to see available statusesfield ls --list-id - Use
withexecute-write-command
to updateentry field - Or use:
promptchange-status
Tips
- Entity types:
,person
,companyopportunity - Interaction types:
,call
,meeting
,email
,chat_messagein_person - Dossier is comprehensive:
returns relationship strength, interactions, notes, and list memberships in one callget-entity-dossier - Use names directly: Most commands accept names instead of IDs (e.g.,
)person ls --query "John" - Finding entities in a list: Use
with filters:query{"from": "listEntries", "where": {"and": [{"path": "listName", "op": "eq", "value": "Dealflow"}, {"path": "entityName", "op": "contains", "value": "Acme"}]}} - Output formats: The
parameter controls result format:format
(default for query): 40% fewer tokens, best for bulk queriestoon
: Best for LLM comprehension when analyzing datamarkdown
: Full structure with envelope - supports cursor pagination for large resultsjson
: For spreadsheet exportcsv- All formats support cursor pagination when results are truncated (use
to resume)nextCursor
Troubleshooting
If tools aren't working or returning unexpected results:
Enable Debug Mode
# Enable (persistent, works with any MCP client) mkdir -p ~/.config/xaffinity-mcp && touch ~/.config/xaffinity-mcp/debug # Restart the MCP client (Claude Desktop: Cmd+Q, reopen) # Disable when done rm ~/.config/xaffinity-mcp/debug
View Logs
Claude Desktop:
tail -f ~/Library/Logs/Claude/mcp-server-*.log
Debug logs show component prefixes like
[xaffinity:tool:1.2.3] to identify which component produced each message.
Common Issues
| Symptom | Likely Cause | Fix |
|---|---|---|
| Tools show old behavior after update | Cached MCP server process | Fully quit and restart Claude Desktop |
| API key errors | Key not configured | Run |
| CLI version errors | Outdated CLI | Run |