Primary skill for Affinity CRM data access when MCP tools are available (discover-commands, execute-read-command, execute-write-command, query, get-entity-dossier). Prefer this over direct CLI when MCP tools are present. Use for entity lookup, pipeline review, meeting prep, warm intros, interaction logging, or when user mentions "pipeline", "deals", "relationship strength", "prepare briefing", or wants to log calls/meetings.
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.
You MUST complete steps 1-2 before running ANY queries or commands.
Skipping these steps leads to incorrect or inefficient queries because:
--with-interaction-dates) may exist that you don't know aboutlist export vs company ls) that you'll missxaffinity://data-model using read-xaffinity-resourcediscover-commands for your specific taskExample:
"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..."
Only use tools or prompts that modify CRM data when the user explicitly asks to do so.
Write operations include:
execute-write-commandlog-interaction-and-update-workflow, change-status, log-call, log-messageRead-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.
The MCP gateway enforces pagination limits to prevent unbounded data scans:
| Limit | Value | Description |
|---|---|---|
| Default | 1000 records | Applied when no --max-results specified |
| Maximum | 10000 records | Higher values are capped with a warning |
--all flag | BLOCKED | Use --max-results 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.
The CLI Gateway provides full access to the xaffinity CLI:
| Tool | Use Case |
|---|---|
discover-commands | Search CLI commands by keyword (e.g., "create person", "export list") |
execute-read-command | Execute read-only CLI commands (get, search, list, export) |
execute-write-command | (write) Execute write CLI commands (create, update, delete) |
Usage pattern:
discover-commands(query: "create person", category: "write")execute-write-command(command: "person create", argv: ["--first-name", "John", "--last-name", "Doe"])| Tool | Use Case |
|---|---|
get-entity-dossier | Comprehensive entity info (details, relationship strength, interactions, notes, list memberships) |
read-xaffinity-resource | Access dynamic resources via xaffinity:// URIs |
Commands that delete data require double confirmation:
execute-read-command to show what will be deletedconfirm: trueExample flow:
User: "Delete person 123"
You: execute-read-command(command: "person get", argv: ["123"])
You: "This will permanently delete John Smith (ID: 123, email: [email protected]).
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)
Use query tool for:
Use individual CLI commands for:
person get 123, company get 456person ls --query "John", company ls --query "Acme"list ls, field ls --list-id <id>⚠️ 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 expand or include, ALWAYS use dryRun: true first to see estimated API calls. These cause N+1 API calls (one per record) and can be slow or timeout.
// 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"]}
⚠️ 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.
| Command | Use Case |
|---|---|
person ls --query "..." | Quick search persons by name/email |
company ls --query "..." | Quick search companies |
list ls | List all Affinity lists |
field ls --list-id <id> | Get field definitions and dropdown options |
Note: For list exports needing relationships or computed data, use query instead of list export.
| Command | Use Case |
|---|---|
person get <id> | Get person details |
company get <id> | Get company details |
opportunity get <id> | Get opportunity details |
relationship-strength ls --external-id <id> | Get relationship strength for a person |
interaction ls --person-id <id> --type all | Get all interactions (or use specific type: email, meeting, call, chat-message) |
field history <field-id> --person-id <id> | Audit who changed a field and when. Use to track status changes or investigate field modifications. Requires exactly one entity selector: --person-id, --company-id, --opportunity-id, or --list-entry-id |
| Command | Use Case |
|---|---|
interaction create --type call --person-id <id> | Log a call/meeting/email |
note create --person-id <id> --content "..." | Add a note |
entry field "<list>" <entryId> --get <field> | Read field values (returns resolved person/company objects) |
entry field "<list>" <entryId> --set <field> <value> | Update a field value |
person create --first-name "..." --last-name "..." | Create a person |
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 |
|---|---|---|
prepare-briefing | read-only | User has upcoming meeting, needs context on a person/company |
pipeline-review | read-only | User wants weekly/monthly pipeline review |
warm-intro | read-only | User wants to find introduction path to someone |
interaction-brief | read-only | Get interaction history summary for an entity |
log-interaction-and-update-workflow | write | User explicitly asks to log a call/meeting and update pipeline |
change-status | write | User explicitly asks to move a deal to new stage |
log-call | write | User explicitly asks to log a phone call |
log-message | write | User explicitly asks to log a chat/text message |
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")Access dynamic data via xaffinity:// URIs using read-xaffinity-resource:
| URI | Returns |
|---|---|
xaffinity://me | Current authenticated user details |
xaffinity://me/person-id | Current user's person ID in Affinity |
xaffinity://interaction-enums | Valid interaction types and directions |
xaffinity://saved-views/{listId} | Saved views available for a list |
xaffinity://field-catalogs/{listId} | Field definitions for a list |
xaffinity://workflow-config/{listId} | Workflow configuration for a list |
Combine the tools above to handle multi-step tasks:
get-entity-dossier for full context, or prepare-briefing promptexecute-write-command to log interaction, query to find list entry, entry field to update status — or log-interaction-and-update-workflow promptperson ls → relationship-strength ls, or warm-intro promptquery with aggregation + expand, or pipeline-review prompt⚠️ Complete the pre-flight checklist before using any pattern.
person, company, opportunitycall, meeting, email, chat-message (or chat)get-entity-dossier returns relationship strength, interactions, notes, and list memberships in one callperson ls --query "John")query with filters:
{"from": "listEntries", "where": {"and": [{"path": "listName", "op": "eq", "value": "Dealflow"}, {"path": "entityName", "op": "contains", "value": "Acme"}]}}
format parameter controls result format:
toon (default for query): 40% fewer tokens, best for bulk queriesmarkdown: Best for LLM comprehension when analyzing datajson: Full structure with envelope - supports cursor pagination for large resultscsv: For spreadsheet exportnextCursor to resume)If tools aren't working or returning unexpected results:
# 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
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.
| 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 xaffinity config setup-key |
| CLI version errors | Outdated CLI | Run pip install --upgrade "affinity-sdk[cli]" |