redtail-mcp

redtail-mcp

MCP server that exposes Redtail CRM's TWAPI as tools, enabling CRM operations like contacts, activities, and onboarding via natural language.

Category
Visit Server

README

redtail-mcp

An agent-agnostic FastMCP stdio server that exposes the Redtail CRM public API (TWAPI) as Model Context Protocol tools.

Any MCP client can drive it — Claude Desktop, Claude Code, or a custom agent built on the Claude Agent SDK or another MCP-aware framework. The server speaks JSON-RPC over stdio; stdout is the protocol stream, all logs go to stderr.

Two things distinguish it from a thin wrapper:

  • Firm-identity externalization. No advisor names, user ids, rep codes, or activity-code labels live in the tool modules. config.py loads them from JSON env vars (with placeholder defaults) so the same binary serves a different firm by pointing at a different .env.
  • Multi-user attribution. Optionally set REDTAIL_USER_KEYS to a map of {name: durable_user_key}. When a write tool is called with an acting_user argument, the server authenticates as that user via Redtail's UserKeyAuth, so the new record's added_by is stamped with the real person — on one shared API subscription.

Install

Requires Python 3.11 and uv.

git clone https://github.com/your-org/redtail-mcp.git
cd redtail-mcp
uv sync
cp .env.example .env    # then fill in the three required secrets

Configuration

Everything the server reads at boot is documented inline in .env.example. At minimum you must set:

Variable Purpose
TWAPI_API_KEY TWAPI subscription key from the Redtail developer portal.
TWAPI_USERNAME Shared-account login (fallback attribution for writes).
TWAPI_PASSWORD Shared-account password.

Optional — override placeholder defaults to make the server your firm's:

Variable Purpose
REDTAIL_USER_KEYS JSON {name: user_key} for per-user write attribution. Secret; env-only.
REDTAIL_DEFAULT_USER_ID User id used as the attendee floor / default owner.
REDTAIL_TEAM_MAP JSON {name: user_id} — resolves friendly names in tool args.
REDTAIL_REP_ADVISOR_MAP JSON {rep_code: {routing}} — drives onboarding + call defaults.
REDTAIL_ACTIVITY_CODE_LEGEND JSON {id: name} — friendly names for activity codes.
REDTAIL_ALLOWED_TOOLS CSV allowlist — trim the exposed catalog without removing capability.
TWAPI_BASE_URL, TWAPI_MAX_RETRIES, TWAPI_CONCURRENCY, LOG_LEVEL Transport tuning.

The server fails loud (sys.exit 2) at boot on a missing credential or a malformed JSON map — a misconfigured deployment dies instead of silently mis-routing writes.

Register with Claude Desktop

Add an entry under mcpServers in claude_desktop_config.json:

{
  "mcpServers": {
    "redtail": {
      "command": "uv",
      "args": [
        "--directory", "/path/to/redtail-mcp",
        "run", "python", "server.py"
      ]
    }
  }
}

Restart Claude Desktop; the redtail server should appear in the MCP panel with its tools listed.

Register with Claude Code

claude mcp add redtail -- uv --directory /path/to/redtail-mcp run python server.py

Or add it to a project's .mcp.json:

{
  "mcpServers": {
    "redtail": {
      "command": "uv",
      "args": ["--directory", "/path/to/redtail-mcp", "run", "python", "server.py"]
    }
  }
}

Tool reference

43 tools are implemented across four modules. The default catalog exposes them all; narrow it with REDTAIL_ALLOWED_TOOLS.

Activities (tools_activities.py)

Tool Purpose Key args
get_agenda One person's or the team's activities for today / a range. user_ids?, date_range?
get_overdue_activities Every open activity past its due date. user_ids?
get_activities_in_range Activities in an explicit ISO date range. start, end, user_ids?
get_activity Fetch a single activity by id. activity_id
get_contact_activity_history Activity history for one contact. contact_id, kind?
create_task Create a task activity (owner defaults resolved from name). subject, contact_id?, due_date?, user_ids?, acting_user?
log_call Log a completed phone call against a contact. contact_id, subject, note?, acting_user?
add_note Add a durable note as a logged activity. contact_id, note, acting_user?
complete_activity Mark an activity done with an optional result. activity_id, result?, acting_user?
reschedule_activity Move an activity's start / end. activity_id, new_start, new_end?, acting_user?
assign_activity Change an activity's owner / attendees. activity_id, user_ids, acting_user?
create_activity General activity create with full field control. subject, activity_code_id, start, end?, ...
update_activity Patch fields on an existing activity. activity_id, patch, acting_user?
batch_update_activities Apply the same patch across many activities. activity_ids, patch, acting_user?
delete_activity Delete an activity. activity_id, acting_user?

Contacts (tools_contacts.py)

Tool Purpose Key args
search_contacts Full-text contact search. q, limit?
find_contact_by_email Exact-email lookup. email
get_contact Full contact record. contact_id
get_contact_notes Notes attached to a contact. contact_id
get_important_info Memberships / important-info sheet. contact_id
get_professional_contacts Attorneys / CPAs / other advisors linked to a contact. contact_id
get_family Family + spouse links. contact_id
get_contact_photo Profile photo URL. contact_id
get_household Household record. household_id
resolve_contact Fuzzy identity resolution — "which contact do you mean?". q
create_contact Create a new contact. first_name, last_name, ...
update_contact Patch fields on an existing contact. contact_id, patch, acting_user?
add_phone Add a phone number. contact_id, number, type?, acting_user?
add_email Add an email address. contact_id, email, type?, acting_user?
add_address Add a mailing address. contact_id, street, city, state, zip, type?, acting_user?
link_family Link a family relationship. contact_id, related_id, relation, acting_user?
add_tag_member Put a contact on a tag (cohort). tag, contact_id, acting_user?
add_contact_keyword Add a keyword to a contact. contact_id, keyword, acting_user?
update_important_info Patch important-info fields. contact_id, patch, acting_user?
remove_contact_subresource Remove a phone / email / address / etc. contact_id, resource, resource_id, acting_user?

Onboarding (tools_onboarding.py)

Tool Purpose Key args
create_onboarding_tasks Example workflow: create a bundle of onboarding tasks for a new client, routed off the rep code. Override the plan by passing tasks=[...]. contact_id, rep_code, effective_date?, tasks?, acting_user?

Reference (tools_reference.py)

Tool Purpose Key args
list_database_users Enumerate every user in the Redtail database.
list_activity_codes Enumerate activity codes.
list_contact_categories Enumerate contact categories.
list_tags Enumerate tags.
list_tag_members List contacts on a tag (cohort). tag
list_contacts Filtered contact list (category / status / updated-since). category_id?, status_id?, updated_since?
remove_tag_member Take a contact off a tag. tag, contact_id

Usage examples

Once the server is registered, natural-language prompts flow through the tools. All examples below use the fictional client Jane Sample.

Read. "Who's on my calendar this week?" — the client calls get_agenda with user_ids resolved from the caller's name via REDTAIL_TEAM_MAP.

Write with default attribution. "Log a call with Jane Sample: reviewed her rollover paperwork, will send the DocuSign tomorrow." — the client calls log_call(contact_id=..., subject="Rollover paperwork review", note="..."). The record's added_by is the shared TWAPI user.

Write with per-user attribution. With REDTAIL_USER_KEYS populated and an agent that tags the inbound user (e.g. [alice|100001]), pass acting_user="alice" on any write tool. The server switches to UserKeyAuth for that call and Redtail stamps the record as coming from Alice — even though the API subscription is shared.

Onboarding. "Start onboarding for Jane Sample, rep code REP01." — create_onboarding_tasks(contact_id=..., rep_code="REP01") creates the example task bundle, routed to the owner mapped in REDTAIL_REP_ADVISOR_MAP.

Development

uv sync --extra dev
uv run pytest
uv run python tests/smoke_stdio.py

DESIGN.md covers the architecture — request path, auth model, per-user attribution decision, truncation contract, and the firm-identity externalization pattern.

License

MIT. See LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured