mcp-crm

API Reference

16 MCP tools exposed by mcp-crm server. Connected AI agents discover these automatically via the MCP listTools protocol. This page is a human-readable reference and is also available as JSON at /api/tools.

Explore (1)

describe_schema

Explore

Introspect the subset of 08Liter tables exposed by this MCP server. Use this first to learn what fields are available before calling query tools.

Parameters

NameTypeReqDescription
tableenumbrand | partner | partner_admin | campaign | category_brand | brand_email | partner_contract | partner_deposit_transaction. Omit for table list.
Returns: Table list with approx row counts, or column details for a specific table.

Example

{
  "table": "brand"
}

Returns 20 columns including category_id, president, follow_count

Query (read 08L) (9)

list_categories

Query (read 08L)

08Liter canonical category tree. Top-level: λ·°ν‹°(12), νŒ¨μ…˜(13), 라이프(14), μ‹ν’ˆ(33), μœ μ•„(34), μ·¨λ―Έ(35), λ°˜λ €λ™λ¬Ό(6666).

Parameters

NameTypeReqDescription
parentIdnumberReturn children of this category. Omit for top-level (parent_id=0).
languageenumko | en | ja | cn | vi | in (default: ko)
Returns: Array of { id, parent_id, name }.

Example

{
  "parentId": 12,
  "language": "ko"
}

λ·°ν‹° ν•˜μœ„ μΉ΄ν…Œκ³ λ¦¬: κΈ°λ³Έ μΌ€μ–΄, μŠ€νŽ˜μ…œ μΌ€μ–΄, ν΄λ Œμ§•, μ„ μΌ€μ–΄, ...

search_brands

Query (read 08L)

Search 08Liter brands with CRM-relevant filters. Returns brand identity, category, most-recent-campaign date, and a single contactable partner_admin.

Parameters

NameTypeReqDescription
categoryIdnumberFilter by category (use list_categories to resolve names)
countryCodestringe.g. "82" for Korea
lastCampaignBeforeISO dateBrands whose most recent campaign started before this date (dormant filter)
lastCampaignAfterISO dateBrands whose most recent campaign started after this date (active filter)
hasVerifiedContactbooleanRequire at least one verified partner_admin email (default: true)
keywordstringSubstring match against brand.president or partner.name
limitnumber1-200 (default: 50)
offsetnumberPagination offset (default: 0)
Returns: Array of brands with partner_name, category_id, last_campaign_at, total_campaigns, primary_contact_email/name.

Example

{
  "categoryId": 12,
  "lastCampaignBefore": "2025-01-01",
  "hasVerifiedContact": true,
  "limit": 5
}

Dormant beauty brands with verified contact β€” the classic reactivation scenario

get_brand

Query (read 08L)

Drill into a single brand: full profile, parent partner, ALL verified contacts, N most-recent campaigns, current liter balance.

Parameters

NameTypeReqDescription
brandIdnumberβœ“brand.id from search_brands
recentCampaignsLimitnumber0-20 (default: 5)
Returns: brand profile, verified_contacts[], liter_balance, total_campaigns, last_campaign_at, recent_campaigns[].

Example

{
  "brandId": 13579,
  "recentCampaignsLimit": 3
}

Returns ν•œκ΅­ν™”μž₯ν’ˆ(μ£Ό) with 1,070,000 Liter balance, μ„œν˜„μ„ νŒ€μž₯ contact, cushion campaign history

search_partner_contacts

Query (read 08L)

List ALL verified partner_admin contacts for a partner. Use when you need multiple contacts for CC or multi-recipient outreach.

Parameters

NameTypeReqDescription
partnerIdnumberβœ“partner.id
includeInactivebooleanInclude non-READY admins (default: false)
Returns: Array of { id, admin_name, email, role, position, mobile_phone_number, status }.

search_campaigns

Query (read 08L)

Search 08Liter campaigns. Common status_codes: 1206=accepting, 1208=review, 1209=closed, 1210=cancelled, 1211=rejected.

Parameters

NameTypeReqDescription
partnerIdnumberFilter by partner
statusCodesstring[]4-char codes like ["1209"]
startedAfterISO datecampaign.start_at after this
startedBeforeISO datecampaign.start_at before this
keywordstringSubstring match on campaign name
minApplyCountnumberMinimum applicants
limitnumber1-200 (default: 50)
offsetnumberPagination offset (default: 0)
Returns: Array of campaigns with partner_name, status_code, dates, offer/apply counts, price.

Example

{
  "startedAfter": "2024-10-01",
  "minApplyCount": 100,
  "limit": 10
}

High-traction campaigns for reference when drafting outreach

get_campaign_performance

Query (read 08L)

Engagement snapshot for a single campaign: raw counts plus derived ratios (fill rate, oversubscription, apply-per-view).

Parameters

NameTypeReqDescription
campaignIdnumberβœ“campaign.id
Returns: campaign details, metrics { fill_rate, oversubscription_ratio, apply_per_view }, interpretation string.

list_segments

Query (read 08L)

List existing CRM segments in crm-pg. Use to discover what target lists exist before creating duplicates.

Parameters

NameTypeReqDescription
limitnumber1-100 (default: 20)
kindenumpartner | brand | campaign
Returns: Array of { id, name, kind, target_count, draft_count, created_by, created_at }.

list_drafts

Query (read 08L)

List existing email drafts with status, target count, segment info. Use to discover campaigns in progress.

Parameters

NameTypeReqDescription
limitnumber1-100 (default: 20)
statusenumdraft | in_review | approved | rejected | sent | cancelled
Returns: Array of { id, name, status, target_count, segment, created_by, created_at, queued_at, sent_at }.

list_menu_groups

Query (read 08L)

List dynamic menu groups and their items in the admin UI. Use to discover existing menus before creating new ones, or to find slugs for upsert_dynamic_page.

Parameters

NameTypeReqDescription
includeFixedbooleanInclude built-in groups (System, Admin) (default: false)
Returns: Array of { id, name, slug, icon, is_fixed, items: [{ id, name, slug, href, has_page }] }.

Author (write CRM) (2)

create_segment

Author (write CRM)

Persist a named target list in crm-pg. Use after search_brands / search_campaigns to freeze results, then pass segment_id to save_message_draft.

Parameters

NameTypeReqDescription
namestringβœ“Segment name
kindenumβœ“partner | brand | campaign
descriptionstringHuman-readable note
createdBystringActor identifier
targetsarrayβœ“{ externalId: number, snapshot: object }[] β€” each row from the search tool
Returns: { segment_id, name, kind, target_count, created_at }

save_message_draft

Author (write CRM)

Persist an AI-generated email campaign with per-target rendering. Creates draft status β€” NOT sent until a human approves via the review gate.

Parameters

NameTypeReqDescription
segmentIdstringβœ“From create_segment
namestringβœ“Campaign name
subjectTemplatestringβœ“Default subject line
bodyTemplatestringβœ“Default body (HTML or plaintext)
senderNamestringFrom name (default: 08Liter CRM)
senderEmailstringFrom email (default: crm@08liter.com)
createdBystringActor
targetsarrayβœ“{ externalId, toEmail, toName?, subject?, body?, context? }[] β€” per-target overrides for personalization
Returns: { draft_id, segment_id, name, status, target_count, created_at }

Control (1)

queue_for_review

Control

Hand a draft to human reviewers via the crm-web review gate. Transitions draft β†’ in_review. The MCP server NEVER sends email; after this, reviewers approve/reject per target then click Send.

Parameters

NameTypeReqDescription
draftIdstringβœ“From save_message_draft
actorstringWho queued it
notestringContext for the reviewer
Returns: { draft_id, status, queued_at, target_count, review_url_hint }

Admin (menu/page) (3)

create_menu_group

Admin (menu/page)

Create a top-level menu group (tab) in the admin UI header. Groups contain sidebar items added via create_menu_item.

Parameters

NameTypeReqDescription
namestringβœ“Display name (e.g. "CRM")
slugstringβœ“URL-safe slug, lowercase with hyphens
iconstringEmoji icon (e.g. "πŸ“Š")
positionnumberSort order (lower = more left) (default: 10)
Returns: { group_id, name, slug, icon }

Example

{
  "name": "CRM",
  "slug": "crm",
  "icon": "πŸ“Š"
}

Creates a new CRM tab in the header

create_menu_item

Admin (menu/page)

Add a sidebar menu item under a group. Dynamic pages render at /p/{groupSlug}/{itemSlug}. Call upsert_dynamic_page next to define content.

Parameters

NameTypeReqDescription
groupSlugstringβœ“Parent group slug
namestringβœ“Display name
slugstringβœ“URL-safe slug
iconstringEmoji
hrefstringCustom href (omit for auto /p/{group}/{slug})
positionnumberSort order (default: 0)
Returns: { item_id, group, name, slug, page_url }

upsert_dynamic_page

Admin (menu/page)

Create or update page content at /p/{groupSlug}/{itemSlug}. Sections define layout: "text" (HTML), "stats" (metric cards), "table" (data grid). Put search_brands/search_campaigns results directly into table rows.

Parameters

NameTypeReqDescription
groupSlugstringβœ“Menu group slug
itemSlugstringβœ“Menu item slug
titlestringβœ“Page title
descriptionstringSubtitle
createdBystringActor
sectionsarrayβœ“Array of section objects. Types: { type: "text", title?, content: "<html>" } | { type: "stats", title?, items: [{ label, value }] } | { type: "table", title?, columns: string[], rows: object[] }
Returns: { page_id, url, title, section_count, action: "created"|"updated" }

Example

{
  "groupSlug": "crm",
  "itemSlug": "dormant",
  "title": "휴면 λΈŒλžœλ“œ",
  "sections": [
    {
      "type": "stats",
      "items": [
        {
          "label": "Total",
          "value": 47
        }
      ]
    },
    {
      "type": "table",
      "columns": [
        "partner_name",
        "last_campaign_at"
      ],
      "rows": []
    }
  ]
}

Creates a page with stats + table at /p/crm/dormant

Safety constraints

  • No send tool β€” MCP never sends email. queue_for_review hands off to a human reviewer.
  • Read-only 08L β€” All zeliter queries use SET SESSION TRANSACTION READ ONLY. No INSERT/UPDATE/DELETE.
  • B2C blocked β€” member.marketing_consent is 100% NULL. No member marketing until 08L adds a real consent mechanism.
  • Row cap β€” Every query is clamped to MCP_MAX_ROW_LIMIT (default 1000). Response includes clamped_by if triggered.
  • Audit trail β€” Every tool call is logged to crm-pg AuditEntry + stderr. Viewable at /audit.
  • Suppression list β€” Bounced/unsubscribed/complained addresses in Suppression table are excluded at send time.

Typical agent flow

  1. 1. list_categories β†’ pick target category
  2. 2. search_brands β†’ find dormant/active brands
  3. 3. get_brand β†’ deep-dive for personalization context
  4. 4. create_segment β†’ save the target list
  5. 5. save_message_draft β†’ generate per-target personalized emails
  6. 6. queue_for_review β†’ hand off to human at /drafts/[id]
  7. 7. Human approves/rejects per target, clicks Send β†’ dry_run or SendGrid