Skip to main content
Glama
keap-mcp

keap-mcp

keap-mcp

Keap (formerly Infusionsoft) MCP Service — a stateless HTTP MCP server wrapping the Keap CRM REST API v1, covering Contacts, Tags, Opportunities, Notes, Tasks, Campaigns, and Users.

Tech stack: Python 3.12 + uv + FastMCP (Starlette/Uvicorn)

It follows the MSPbots Vendor MCP Service SOP: stateless, no stored credentials, per-request header authentication only (no environment-variable fallback).

MSPbots Connector

The MCP Gateway built for MSPs: visible, controlled, and your data stays where it belongs.

Get started at connect.mspbots.ai →


MSPbots Connector gives your AI clients one MCP URL to reach your entire MSP stack (RMM, PSA, documentation, security, finance), and gives you control over who can call which tool and a record of everything that was called.

Hosted service: connect.mspbots.ai · Free to use.

Why Connector

MSPbots Connector

Visible

Every tool call is logged: who, which vendor, when. Usage dashboard, CSV export, SIEM streaming.

Controlled

Role-based, per-tool allowlist. Deny by default.

Protected

Credentials encrypted per record. AI clients never see your vendor passwords or tokens.

MSP-native

Built for the MSP stack only: RMM, PSA, documentation, security, finance.

Quick start

  1. Sign up at connect.mspbots.ai.

  2. Connect your vendors. Pick from 150+ connectors and authorize each one on the vendor's own page, or bring your own API keys. No extra vendor accounts needed.

  3. Set access. Create roles and decide which tools each role may call. Nothing is allowed until you allow it.

  4. Add your MCP URL to your AI client. Copy the URL from your Connector dashboard into Claude, ChatGPT, Cursor, VS Code, Gemini, Codex, or any MCP-capable client.

  5. Ask your AI to do real work, and watch every call appear in the audit log.

Features

Unified gateway

  • One MCP URL for all your AI clients

  • 150+ connectors across the MSP stack

  • Custom MCP servers supported, free

  • Authorization happens on each vendor's own page; the AI never sees passwords or tokens

  • Bring your own credentials: use the vendor API keys you already have

  • Multiple accounts per app; connect once, reuse across AI clients

  • Tool search: finds the right action for the task

  • One sign-in; vendor credentials are injected behind the scenes and OAuth tokens refresh automatically

Visibility

  • Audit log for every tool call (who, which vendor, when)

  • Usage dashboard: call volume, top vendors, error rate, per-user activity

  • Export audit logs to CSV, or stream to Loki, Graylog, or LogScale (SIEM)

  • Optional recording of tool arguments and result summaries (off by default, enabled per organization)

Control

  • Per-role, per-tool allowlist, deny by default

  • owner / admin / member roles

  • SCIM provisioning with Entra ID, Okta, JumpCloud, and Google Workspace

Security

  • Credentials encrypted one record at a time (AES-256-GCM, per-record key)

  • AI clients authenticate with OAuth 2.1 + PKCE

  • Vendor responses are scanned for prompt-injection patterns and returned as structured data. This is one layer of defense, not a guarantee against every attack.

  • Static egress IP for customer firewall and API allowlisting

Pricing

Free.

Links: connect.mspbots.ai · mspbots.ai


Related MCP server: mcp-mautic

Scope

Out of Keap's full REST API v1, this service implements 15 tools aligned to the resource categories MSPbots has historically synced (Contact, Tag Contact, Tags, Opportunities, Notes, Task, Campaigns, User).

Authentication

Keap's REST API v1 is oauth2 on paper (authorization_code grant is the only flow in its official OpenAPI spec's securitySchemes), but Keap also offers a documented, self-service alternative that needs no redirect: Personal Access Tokens (PAT) and Service Account Keys (SAK) — see developer.infusionsoft.com/pat-and-sak. Either is generated inside the Keap app itself (Settings → API Settings, no developer-app registration or client secret needed) and used as a plain bearer token:

Authorization: Bearer <PAT or SAK>

This service uses that path — a single static token per tenant, no login/token-exchange step, no redirect. A Service Account Key (admin-level) is recommended over a Personal Access Token (single-user-scoped) for server-to-server use.

Every request to /mcp must include the following HTTP header. The token is read only from this header on every request (via a request-scoped contextvar) — it is never cached, never falls back to an environment variable, and is discarded as soon as the request completes, so concurrent requests from different tenants can never see each other's credentials.

Quick Start

docker compose up --build

The server starts on http://localhost:8080.

Local (uv)

uv sync
python -m keap_mcp

Health Check

curl http://localhost:8080/health
# {"status": "ok"}

No credentials are required for the health endpoint.

HEADER Authorization Parameters

Header

Type

Required

Default

Allowed values

Description

Example

X-Keap-Access-Token

string

Yes

None

None

Keap Personal Access Token or Service Account Key (generated in the Keap admin under Settings → API Settings); this service forwards it as-is as Authorization: Bearer

KeapAK-a1b2c3d4e5f6g7h8i9j0

Missing the header returns 401 Unauthorized with the required header name listed in the response body.

Environment Variables

Variable

Default

Description

MCP_HTTP_PORT

8080

Listening port

MCP_HTTP_HOST

0.0.0.0

Listening host

No credential fields exist in configuration — the access token is never read from an environment variable in this service; it comes exclusively from the X-Keap-Access-Token request header (see above).

MCP Endpoint

POST http://localhost:8080/mcp

Connect your MCP client with:

  • Transport: http (Streamable HTTP)

  • Headers: X-Keap-Access-Token: <token> (required)

Available Tools (15)

limit parameters below default to 20 and are clamped server-side to a hard cap of 200 (Keap's own API accepts up to 1000 per page, but this service applies the stricter MSPbots token-economy ceiling).

Tool

Description

API

keap_list_contacts

List contacts

GET /contacts

keap_get_contact

Retrieve a contact by ID

GET /contacts/{id}

keap_create_contact

Create a contact

POST /contacts

keap_list_contact_tags

List tags applied to a contact

GET /contacts/{contactId}/tags

keap_apply_tags_to_contact

Apply tags to a contact

POST /contacts/{contactId}/tags

keap_list_tags

List all tags defined in the app

GET /tags

keap_list_opportunities

List sales opportunities (deals)

GET /opportunities

keap_get_opportunity

Retrieve an opportunity by ID

GET /opportunities/{opportunityId}

keap_create_opportunity

Create a sales opportunity

POST /opportunities

keap_list_notes

List notes

GET /notes

keap_create_note

Create a note on a contact

POST /notes

keap_list_tasks

List tasks

GET /tasks

keap_create_task

Create a task

POST /tasks

keap_list_campaigns

List marketing/automation campaigns

GET /campaigns

keap_list_users

List users of the Keap app

GET /users

Tool descriptions in the MCP protocol itself are intentionally short (business-facing "what it does" summary only); full per-parameter documentation lives in each parameter's JSON-schema description (visible via tools/list), not in this table.

Test Example

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "X-Keap-Access-Token: <token>" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": { "name": "keap_list_contacts", "arguments": { "limit": 5 } }
  }'

Known Gaps

  • ⚠️ Not yet tested against a live Keap account. All 15 tools have been checked structurally only (MCP handshake, tools-list, schema validity, /health, gateway 401 credential-gating) — no real PAT/SAK was available at build time. A free-trial Keap account application has been submitted separately; once approved, generate a Service Account Key and test end-to-end.

  • Endpoint paths/params were verified directly against Keap's official OpenAPI v1 spec (https://crm.infusionsoft.com/app/v3/api-docs/V1, linked from the "Download OpenAPI specification" button on the docs site) — not guessed.

  • PUT /contacts (upsert) documents a duplicate_option field in prose but it does not appear in the actual request schema — a documentation/schema mismatch on Keap's side, not implemented here since it's unconfirmed. Not built as a tool in this 15-tool scope anyway (only POST/GET contact operations were included).

  • Scope is limited to the 15 operations above (Contacts/Tags/Opportunities/Notes/Tasks/Campaigns/Users read+core-write), not Keap's full REST API v1 surface (which also includes Companies, Products, Orders/Subscriptions, Affiliates, Files, Email sending, custom fields management, and webhooks).

  • Keap's list endpoints accept limit up to 1000 server-side; this service clamps to 200 (the SOP's hard cap) to bound response size and token cost — a value between 200 and 1000 will silently be reduced to 200 rather than rejected.

API Reference

Available Tools

15 tools
keap_apply_tags_to_contactA

Apply one or more tags to a contact.

    API: POST /contacts/{contactId}/tags

    Args:
        contact_id: The contact's unique ID.
        tag_ids: Required. List of tag IDs to apply.
    

Inputs: tag_ids (required), contact_id (required). Returns: result

keap_create_contactA

Create a contact. Must include at least one email address or phone number.

    API: POST /contacts

    Args:
        given_name: First name.
        family_name: Last name.
        email_addresses: List of dicts, e.g. [{"email": "a@b.com", "field": "EMAIL1"}].
        phone_numbers: List of dicts, e.g. [{"number": "555-0100", "field": "PHONE1"}].
        addresses: List of dicts, e.g. [{"line1": "...", "locality": "...", "region": "...",
            "postal_code": "...", "country_code": "US", "field": "BILLING"}].
        custom_fields: List of dicts, e.g. [{"id": 1, "content": "value"}].
    

Inputs: addresses, given_name, family_name, custom_fields, +2 more. Returns: result

keap_create_noteA

Create a note on a contact. Must include at least a title or body.

    API: POST /notes

    Args:
        contact_id: Required. The contact this note is attached to.
        title: Note title.
        body: Note body text.
        type: One of "Appointment", "Call", "Email", "Fax", "Letter", "Other".
        user_id: The owning user's ID.
    

Inputs: contact_id (required), body, type, title, +1 more. Returns: result

keap_create_opportunityB

Create a sales opportunity (deal).

    API: POST /opportunities

    Args:
        contact_id: Required. The contact ID this opportunity is for.
        stage_id: Required. The pipeline stage ID to place it in.
        opportunity_title: Required. Title of the opportunity.
        user_id: The owning user's ID.
        next_action_date: ISO 8601 date/time for the next action.
        next_action_notes: Notes for the next action.
        opportunity_notes: General notes on the opportunity.
        estimated_close_date: ISO 8601 date for the estimated close.
        projected_revenue_low: Low end of the projected revenue range.
        projected_revenue_high: High end of the projected revenue range.
    

Inputs: stage_id (required), contact_id (required), opportunity_title (required), user_id, +6 more. Returns: result

keap_create_taskA

Create a task. Must include at least a title and due date.

    API: POST /tasks

    Args:
        title: Required. Task title.
        due_date: Required. ISO 8601 date/time the task is due.
        description: Task description.
        type: Task type/category.
        priority: Task priority.
        contact_id: Related contact ID.
        user_id: Assigned user's ID.
        remind_time: Minutes before due_date to remind, one of
            5/10/15/30/60/120/240/480/1440/2880.
    

Inputs: title (required), due_date (required), type, user_id, +4 more. Returns: result

keap_get_contactA

Retrieve a single contact by ID.

    API: GET /contacts/{id}

    Args:
        contact_id: The contact's unique ID.
        optional_properties: Comma-separated list of extra fields to include,
            e.g. "custom_fields,job_title,lead_source_id".
    

Inputs: contact_id (required), optional_properties. Returns: result

keap_get_opportunityA

Retrieve a single opportunity by ID.

    API: GET /opportunities/{opportunityId}

    Args:
        opportunity_id: The opportunity's unique ID.
        optional_properties: Comma-separated list of extra fields to include.
    

Inputs: opportunity_id (required), optional_properties. Returns: result

keap_list_campaignsA

List marketing/automation campaigns.

    API: GET /campaigns

    Args:
        search_text: Free-text search on campaign name.
        limit: Max results per page.
        offset: Pagination offset.
        order: Sort field, e.g. "id", "name", "published_date", "status", "category".
    

Inputs: limit, order, offset, search_text. Returns: result

keap_list_contactsA

List contacts.

    API: GET /contacts

    Args:
        given_name: Filter by first name.
        family_name: Filter by last name.
        email: Filter by email address.
        limit: Max results per page (default 20).
        offset: Pagination offset.
        order: Sort field, e.g. "id", "date_created", "last_updated", "name", "email".
    

Inputs: email, limit, order, offset, +2 more. Returns: result

keap_list_contact_tagsA

List the tags applied to a contact.

    API: GET /contacts/{contactId}/tags

    Args:
        contact_id: The contact's unique ID.
        limit: Max results per page.
        offset: Pagination offset.
    

Inputs: contact_id (required), limit, offset. Returns: result

keap_list_notesB

List notes.

    API: GET /notes

    Args:
        contact_id: Filter by contact ID.
        user_id: Filter by the note's owning user ID.
        limit: Max results per page.
        offset: Pagination offset.
    

Inputs: limit, offset, user_id, contact_id. Returns: result

keap_list_opportunitiesA

List sales opportunities (deals).

    API: GET /opportunities

    Args:
        user_id: Filter by the owning user's ID.
        stage_id: Filter by pipeline stage ID.
        search_term: Free-text search.
        limit: Max results per page.
        offset: Pagination offset.
        order: Sort field, e.g. "next_action", "opportunity_name", "contact_name", "date_created".
    

Inputs: limit, order, offset, user_id, +2 more. Returns: result

keap_list_tagsA

List all tags defined in the app.

    API: GET /tags

    Args:
        category: Filter by tag category ID.
        name: Filter by tag name.
        limit: Max results per page.
        offset: Pagination offset.
    

Inputs: name, limit, offset, category. Returns: result

keap_list_tasksA

List tasks.

    API: GET /tasks

    Args:
        contact_id: Filter by related contact ID.
        user_id: Filter by the assigned user's ID.
        completed: Filter by completion status.
        has_due_date: Filter to tasks that have (or don't have) a due date.
        limit: Max results per page.
        offset: Pagination offset.
        order: Sort field.
    

Inputs: limit, order, offset, user_id, +3 more. Returns: result

keap_list_usersB

List users of the Keap app.

    API: GET /users

    Args:
        include_inactive: Include inactive users.
        include_partners: Include partner users.
        limit: Max results per page.
        offset: Pagination offset.
    

Inputs: limit, offset, include_inactive, include_partners. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 15 tools

    Disambiguation5/5

    Every tool targets a distinct resource or resource+action combination. There is no overlap between listing all tags and listing tags on a contact, and each get/list/create is uniquely identifiable.

    Naming Consistency5/5

    All tools follow the keap_<verb>_<noun> pattern with verbs limited to get, list, create, and apply. No mixed conventions or irregular naming exists.

    Tool Count5/5

    15 tools is within the ideal 3-15 range, and each tool covers a meaningful operation for Keap CRM integration without being excessive.

    Completeness2/5

    The server provides read and create operations for core entities (contacts, opportunities, notes, tasks) but lacks update and delete for most, and no create/update/delete for tags, campaigns, or users. This creates dead ends in common workflows.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      F
      maintenance
      Comprehensive MCP server for the Mautic marketing automation API, providing 203 tools for managing contacts, campaigns, emails, segments, and more.
      2
      ISC
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server for interacting with Keap CRM, enabling contact and tag management, batch operations, custom fields, and advanced query optimization.
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      A comprehensive MCP server for Less Annoying CRM providing 87 tools for contacts, pipelines, tasks, events, notes, emails, files, and more.
      88
      233 npm
      MIT