Skip to main content
Glama
LucasNS231

redtail-mcp

by LucasNS231

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

Related MCP server: libredesk-mcp

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.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    D
    maintenance
    MCP server that exposes the complete Libredesk REST API (54 endpoints) as tools, enabling natural language management of conversations, contacts, agents, teams, and more for the open-source customer support desk.
    54
    6 npm
    3
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    A self-hosted MCP server that connects a Follow Up Boss CRM account to Claude, enabling CRM operations through natural language via 25 curated tools and a raw API tool.
    -