Developers · Apavin MCP

Apavin MCP documentation

Apavin runs a remote Model Context Protocol server for business email and WhatsApp. Transport is Streamable HTTP in stateless mode; authorization is OAuth 2.1 with PKCE and dynamic client registration. Supported protocol versions: 2025-11-25, 2025-06-18, 2025-03-26.

Quickstart

  1. Create a workspace. MCP Developer is free.
  2. Connect an email account (and a WhatsApp number on paid plans) under Settings, Channels.
  3. Open Settings, AI agents (MCP). Check the permissions, then run the connection test on the Connect tab.
  4. Add your endpoint to an MCP client (below). It opens Apavin to sign in; approve the permissions.
  5. Ask your agent to call list_connected_accounts, then search_emails.

Endpoint

Your workspace’s exact URL is shown in the app on the Connect tab. The URL configured for this deployment is:

https://apavin.com/api/mcp

The dedicated host https://mcp.apavin.com/mcp is the planned address. Until it has DNS, TLS and a recorded connection test, use the URL the app shows you. Health check (no data, no auth): https://apavin.com/api/mcp/health.

Authentication

A request without a valid token gets 401 with WWW-Authenticate: Bearer resource_metadata="…". Clients follow it to discover everything else:

  • Protected resource metadata (RFC 9728): /.well-known/oauth-protected-resource plus the resource path
  • Authorization server metadata (RFC 8414): https://apavin.com/.well-known/oauth-authorization-server
  • Dynamic client registration (RFC 7591): https://apavin.com/api/oauth/register (public clients, token_endpoint_auth_method: none)
  • Authorization: https://apavin.com/oauth/authorize (code flow, PKCE S256 required, resource parameter supported)
  • Token: https://apavin.com/api/oauth/token (authorization_code, refresh_token)
  • Revocation (RFC 7009): https://apavin.com/api/oauth/revoke

Access tokens last 60 minutes and are sent only in the Authorization header, never in a URL. Refresh tokens rotate on every use; reusing an old one revokes the connection. Only owners, admins and managers (members who can see every conversation) can approve a client, and the client acts as that member.

Scopes

email:readSearch and read business email
email:draftPrepare email drafts
email:sendSubmit emails to send (a person approves each one unless your admin allows auto-send)
whatsapp:readSearch and read WhatsApp conversations
whatsapp:draftPrepare WhatsApp reply drafts
whatsapp:sendSubmit WhatsApp replies to send (approved by a person by default)
whatsapp:templateSubmit approved WhatsApp template messages
followups:scheduleSchedule follow-ups and cancel them
context:readRead customer profiles and business knowledge
customers:writeAdd notes and follow-up tasks to customer records in Apavin
audit:readRead the MCP activity log

No scope parameter means read and draft scopes only, never sending.

Client setup

None of these has yet been recorded as tested against the live Apavin endpoint; each is marked until it is.

MCP Inspector not yet tested

  1. Run the command below on your computer (needs Node.js).
  2. In the Inspector, choose transport Streamable HTTP and paste the endpoint URL.
  3. Press Connect. Your browser opens Apavin's approval page; sign in and approve.
  4. Open Tools and press List Tools.
npx @modelcontextprotocol/inspector

Claude Code not yet tested

  1. Run the command below in a terminal.
  2. Inside Claude Code, run /mcp and choose apavin to sign in and approve.
claude mcp add --transport http apavin https://apavin.com/api/mcp

Claude (web and desktop) not yet tested

  1. Open Claude's connector settings and add a custom connector.
  2. Paste the endpoint URL as the connector URL.
  3. Connect, then sign in to Apavin and approve when asked.

Cursor not yet tested

  1. Add this to ~/.cursor/mcp.json (or .cursor/mcp.json in a project).
  2. Open Cursor's MCP settings and sign in to apavin when prompted.
{
  "mcpServers": {
    "apavin": {
      "url": "https://apavin.com/api/mcp"
    }
  }
}

VS Code not yet tested

  1. Add this to .vscode/mcp.json in your project.
  2. Start the server from the MCP view and sign in when prompted.
{
  "servers": {
    "apavin": {
      "type": "http",
      "url": "https://apavin.com/api/mcp"
    }
  }
}

Permissions

A tool runs only when all of these allow it: the scope was granted to the client; the workspace admin has the operation switched on; the plan includes it; and the authorizing member’s current role and personal permissions allow it. get_action_permissions reports each permission and, when it is unavailable, which of these refused it. Defaults for a new workspace: reading and drafting on; sending, templates, follow-ups and audit access off.

Approvals and sending

Send tools never report success they cannot prove. Possible status values: pending_approval, scheduled, sending, outcome_unknown, accepted (the mail server or WhatsApp took it), delivered, read (WhatsApp receipts only), sandbox_recorded, failed, denied, cancelled. A boolean sent is true only for accepted, delivered and read. Email has no delivery receipts, so accepted is the furthest Apavin can confirm for email.

Every send requires idempotency_key (8 to 128 characters). Retrying with the same key returns the original action and is not billed; the same key with a different message is refused. Auto-send rules (MCP Growth and Enterprise) never apply to templates, scheduled messages, first messages to new recipients, messages containing a blocked term, or beyond the daily cap.

Sandbox mode

An admin can turn on sandbox mode in MCP settings. Approved sends are then recorded as sandbox_recorded and never handed to a provider, so the full flow can be tried on a real workspace without anything leaving it. Available on every plan.

Example calls

Raw JSON-RPC over HTTP, for testing with curl. MCP clients do this for you.

curl -s https://apavin.com/api/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_emails","arguments":{"query":"invoice","limit":5}}}'
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
  "name":"send_email",
  "arguments":{
    "conversation_id":"<thread id from search_emails>",
    "body":"Thanks for asking. The 20-seat price is in the attached sheet.",
    "reason":"Customer asked for team pricing",
    "idempotency_key":"7d1c2a3e-1f0b-4c3e-9a2d-5b6f7a8c9d0e"
  }}}

// result.structuredContent
{ "action_id": "…", "status": "pending_approval", "sent": false,
  "message": "Waiting for a person to approve this message in Apavin. Nothing has been sent.",
  "approval_url": "…/settings/mcp?tab=approvals&action=…" }

Usage limits

PlanCalls a monthEmailWhatsAppMembers
MCP Developer500101
MCP Business2,000111
MCP Growth10,000535
EnterpriseAgreedAgreedAgreedAgreed
Existing Apavin Pro workspaces2,000AllAllAll

Counted: tool calls that ran, including sends left pending approval. Not counted: refusals, invalid input, provider errors, idempotent repeats, and protocol calls such as initialize and tools/list. The allowance resets on the 1st of each month (UTC). At the limit calls return QUOTA_EXCEEDED; there is no overage charge. Rate limits: 60 calls a minute per connection and 240 per workspace.

Errors

Tool failures are returned as a tool result with isError: true and { "error": { "code", "message", "retryable", "details" } }. Protocol errors use JSON-RPC codes. Messages never contain stack traces, credentials or other workspaces’ data.

INVALID_INPUTArguments did not match the tool's schema. details.issues lists each field. Not billed.
SCOPE_MISSINGThe client was not granted this permission when it was authorized. Reconnect and approve it.
PERMISSION_DENIEDThe workspace admin switched the operation off, or the authorizing member's role does not allow it.
PLAN_FEATUREThe plan does not include the operation (for example sending on MCP Developer).
ACCOUNT_LIMITThe connection named is beyond the plan's account limit.
NOT_FOUNDNo such object in this workspace, or not one this agent may use. Also returned for other workspaces' ids.
NO_CONNECTED_ACCOUNTNo email account or WhatsApp number is connected, or it was disconnected.
ACCOUNT_NEEDS_RECONNECTThe provider rejected the stored credentials. An admin must reconnect the account.
WINDOW_CLOSEDThe WhatsApp 24 hour customer service window is closed. Only an approved template can be sent.
OPTED_OUTThe WhatsApp customer sent STOP. Nothing can be sent until they send START.
TEMPLATE_INVALIDThe template does not exist in that language, is not approved, or the variable count is wrong.
TEMPLATE_VALIDATION_UNAVAILABLEThe WhatsApp connection has no Business Account ID, so templates cannot be checked.
IDEMPOTENCY_CONFLICTThe idempotency_key was already used for a different message.
NOT_CANCELLABLEThe message has started sending or already finished.
QUOTA_EXCEEDEDThe monthly call allowance is used. Resets on the 1st (UTC). No overage charge.
RATE_LIMITEDToo many calls in a minute. details.retryAfterSeconds says when to retry.
MCP_DISABLEDMCP is switched off for the workspace.
PROVIDER_ERRORMeta or the mail server refused or could not be reached. Nothing was sent.
TIMEOUTNo answer in time. For a send, retry with the same idempotency_key to learn the outcome; never a new key.
INTERNALUnexpected failure in Apavin. Nothing was sent.

Tool catalogue

Exactly what tools/list returns. Text written by customers comes back inside fields named untrusted.

search_emails

Permission: email:read · read only

Search email synced into Apavin from the workspace's connected inboxes. Filters combine with AND. Returns message ids, thread ids, subject, sender and a short snippet; call get_email_message or get_email_thread for full text. Covers mail received since the inbox was connected to Apavin.

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "maxLength": 200,
      "description": "Words to find in the subject or body."
    },
    "from": {
      "type": "string",
      "maxLength": 200,
      "description": "Part of the sender's name or address."
    },
    "to": {
      "type": "string",
      "maxLength": 200,
      "description": "Part of a recipient's address."
    },
    "subject": {
      "type": "string",
      "maxLength": 200,
      "description": "Part of the subject line."
    },
    "after": {
      "type": "string",
      "format": "date-time",
      "description": "Only messages at or after this time (ISO 8601)."
    },
    "before": {
      "type": "string",
      "format": "date-time",
      "description": "Only messages at or before this time (ISO 8601)."
    },
    "direction": {
      "type": "string",
      "enum": [
        "inbound",
        "outbound",
        "any"
      ],
      "default": "any"
    },
    "connection_id": {
      "type": "string",
      "maxLength": 64,
      "description": "Limit to one connected inbox (see list_connected_accounts)."
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50,
      "default": 20
    }
  },
  "additionalProperties": false
}

get_email_thread

Permission: email:read · read only

Read every message in one email conversation, oldest first, with the customer it belongs to and the inbox it arrived on.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "default": 50,
      "description": "Most recent N messages."
    }
  },
  "required": [
    "conversation_id"
  ],
  "additionalProperties": false
}

get_email_message

Permission: email:read · read only

Read a single email message in full: headers and body.

Input schema
{
  "type": "object",
  "properties": {
    "message_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "message_id"
  ],
  "additionalProperties": false
}

summarize_email_thread

Permission: email:read · read only

Summarize one email conversation: who is involved, what the customer asked, whether they are waiting on a reply, and the open questions in their last message. Always returns an extracted outline; adds a written summary when the workspace has Apavin AI configured.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "conversation_id"
  ],
  "additionalProperties": false
}

create_email_draft

Permission: email:draft · writes to Apavin only

Save an email draft. Nothing is sent. Pass conversation_id to reply in an existing thread (recipient and subject are filled in from it), or to, subject and body for a new email. By default a copy also lands in the mailbox's own Drafts folder, so it shows up in Gmail or Outlook too; the Apavin draft is the one that is approved and sent.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "maxLength": 64
    },
    "to": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "subject": {
      "type": "string",
      "maxLength": 300
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20000
    },
    "connection_id": {
      "type": "string",
      "maxLength": 64
    },
    "save_to_mailbox": {
      "type": "boolean",
      "default": true,
      "description": "Also put a copy in the mailbox's Drafts folder."
    }
  },
  "required": [
    "body"
  ],
  "additionalProperties": false
}

update_email_draft

Permission: email:draft · writes to Apavin only

Change the recipient, subject or body of a draft that has not been submitted yet.

Input schema
{
  "type": "object",
  "properties": {
    "draft_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "to": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "subject": {
      "type": "string",
      "maxLength": 300
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20000
    },
    "save_to_mailbox": {
      "type": "boolean",
      "default": true,
      "description": "Replace the copy in the mailbox's Drafts folder."
    }
  },
  "required": [
    "draft_id"
  ],
  "additionalProperties": false
}

send_email

Permission: email:send · outbound, approval by default

Submit an email to send from a connected inbox. By default a person must approve it in Apavin first, and the result is status pending_approval: nothing has been sent at that point. Pass draft_id to send a saved draft, or conversation_id plus body to reply in a thread, or to, subject and body for a new email. idempotency_key is required.

Input schema
{
  "type": "object",
  "properties": {
    "draft_id": {
      "type": "string",
      "maxLength": 64
    },
    "conversation_id": {
      "type": "string",
      "maxLength": 64
    },
    "to": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "subject": {
      "type": "string",
      "maxLength": 300
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20000
    },
    "connection_id": {
      "type": "string",
      "maxLength": 64
    },
    "reason": {
      "type": "string",
      "maxLength": 500,
      "description": "Why this email is being sent. Shown to the approver."
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "A unique key for this message, such as a UUID. Retrying with the same key returns the original action instead of sending twice. Use a new key for a new message."
    }
  },
  "required": [
    "idempotency_key"
  ],
  "additionalProperties": false
}

schedule_email_follow_up

Permission: followups:schedule · outbound, approval by default

Schedule a follow-up email in an existing thread for a future time (5 minutes to 90 days ahead). A person approves it first; once approved it goes out at send_at. Cancel it with cancel_scheduled_message.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20000
    },
    "subject": {
      "type": "string",
      "maxLength": 300
    },
    "send_at": {
      "type": "string",
      "format": "date-time",
      "description": "When to send, ISO 8601 with offset."
    },
    "reason": {
      "type": "string",
      "maxLength": 500
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "A unique key for this message, such as a UUID. Retrying with the same key returns the original action instead of sending twice. Use a new key for a new message."
    }
  },
  "required": [
    "conversation_id",
    "body",
    "send_at",
    "idempotency_key"
  ],
  "additionalProperties": false
}

get_email_delivery_status

Permission: email:read · read only

Status of an email submitted through send_email or schedule_email_follow_up: pending_approval, scheduled, accepted (the mail server took it), failed, denied or cancelled. Email has no delivery receipts, so accepted is the furthest Apavin can confirm.

Input schema
{
  "type": "object",
  "properties": {
    "action_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "action_id"
  ],
  "additionalProperties": false
}

search_whatsapp_conversations

Permission: whatsapp:read · read only

Find WhatsApp conversations by customer name, phone number or words in the messages. Returns conversation ids with the latest message and whether the 24 hour reply window is open.

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "maxLength": 200,
      "description": "Words in the messages or the customer's name."
    },
    "phone": {
      "type": "string",
      "maxLength": 20,
      "description": "All or part of the customer's number."
    },
    "status": {
      "type": "string",
      "enum": [
        "open",
        "pending",
        "closed",
        "any"
      ],
      "default": "any"
    },
    "after": {
      "type": "string",
      "format": "date-time",
      "description": "Only conversations active at or after this time."
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50,
      "default": 20
    }
  },
  "additionalProperties": false
}

get_whatsapp_conversation

Permission: whatsapp:read · read only

Read the messages in one WhatsApp conversation, oldest first, with the customer, the number it is on, the reply window and opt-out state.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "default": 50
    }
  },
  "required": [
    "conversation_id"
  ],
  "additionalProperties": false
}

get_whatsapp_message

Permission: whatsapp:read · read only

Read a single WhatsApp message and its delivery status.

Input schema
{
  "type": "object",
  "properties": {
    "message_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "message_id"
  ],
  "additionalProperties": false
}

create_whatsapp_reply_draft

Permission: whatsapp:draft · writes to Apavin only

Save a draft reply for a WhatsApp conversation. Nothing is sent. The result says whether the reply window is open, since a free-form reply cannot be sent once it closes.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    }
  },
  "required": [
    "conversation_id",
    "body"
  ],
  "additionalProperties": false
}

send_whatsapp_reply

Permission: whatsapp:send · outbound, approval by default

Submit a free-form reply in a WhatsApp conversation. Only allowed while the 24 hour customer service window is open and the customer has not opted out. By default a person approves it first and the result is pending_approval: nothing has been sent at that point. idempotency_key is required.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "maxLength": 64
    },
    "draft_id": {
      "type": "string",
      "maxLength": 64
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    },
    "reason": {
      "type": "string",
      "maxLength": 500
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "A unique key for this message, such as a UUID. Retrying with the same key returns the original action instead of sending twice. Use a new key for a new message."
    }
  },
  "required": [
    "idempotency_key"
  ],
  "additionalProperties": false
}

send_whatsapp_template

Permission: whatsapp:template · outbound, approval by default

Submit an approved WhatsApp template message, the only kind Meta allows outside the 24 hour window or as a first message. Apavin checks the template exists, is approved at Meta in that language, and that the number of variables matches. A person always approves template sends. Meta charges for template messages on the workspace's own WhatsApp account.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "maxLength": 64
    },
    "to": {
      "type": "string"
    },
    "connection_id": {
      "type": "string",
      "maxLength": 64
    },
    "template_name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "language": {
      "type": "string",
      "minLength": 2,
      "maxLength": 15,
      "description": "Template language code exactly as approved at Meta, e.g. en, en_US, hi."
    },
    "body_params": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 1024
      },
      "maxItems": 20,
      "default": [],
      "description": "Values for {{1}}, {{2}} ... in the template body, in order."
    },
    "reason": {
      "type": "string",
      "maxLength": 500
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "A unique key for this message, such as a UUID. Retrying with the same key returns the original action instead of sending twice. Use a new key for a new message."
    }
  },
  "required": [
    "template_name",
    "language",
    "idempotency_key"
  ],
  "additionalProperties": false
}

schedule_whatsapp_follow_up

Permission: followups:schedule · outbound, approval by default

Schedule a WhatsApp follow-up for a future time (5 minutes to 90 days ahead). Give template_name to send an approved template, which works whenever it is sent; or body for a free-form message, which Apavin will refuse to send if the 24 hour window has closed by then. A person approves it first.

Input schema
{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "send_at": {
      "type": "string",
      "format": "date-time"
    },
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    },
    "template_name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "language": {
      "type": "string",
      "minLength": 2,
      "maxLength": 15,
      "description": "Template language code exactly as approved at Meta, e.g. en, en_US, hi."
    },
    "body_params": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 1024
      },
      "maxItems": 20,
      "default": [],
      "description": "Values for {{1}}, {{2}} ... in the template body, in order."
    },
    "reason": {
      "type": "string",
      "maxLength": 500
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "A unique key for this message, such as a UUID. Retrying with the same key returns the original action instead of sending twice. Use a new key for a new message."
    }
  },
  "required": [
    "conversation_id",
    "send_at",
    "idempotency_key"
  ],
  "additionalProperties": false
}

cancel_scheduled_message

Permission: followups:schedule · writes to Apavin only

Cancel an email or WhatsApp message that is waiting for approval or scheduled for later. A message that has started sending cannot be cancelled.

Input schema
{
  "type": "object",
  "properties": {
    "action_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "action_id"
  ],
  "additionalProperties": false
}

get_whatsapp_delivery_status

Permission: whatsapp:read · read only

Status of a WhatsApp message submitted through Apavin MCP: pending_approval, scheduled, accepted, delivered, read, failed, denied or cancelled, from WhatsApp's own delivery receipts.

Input schema
{
  "type": "object",
  "properties": {
    "action_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    }
  },
  "required": [
    "action_id"
  ],
  "additionalProperties": false
}

get_reply_queue

Permission: context:read · read only

Every open email and WhatsApp conversation where the customer wrote last and nobody has answered, oldest first. Includes how long they have waited, the start of their message, whether a reply is already waiting for approval, and for WhatsApp how long the 24 hour reply window has left. Use it to start the day, or before asking which conversations need attention.

Input schema
{
  "type": "object",
  "properties": {
    "channel": {
      "type": "string",
      "enum": [
        "email",
        "whatsapp",
        "any"
      ],
      "default": "any"
    },
    "min_wait_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 43200,
      "default": 0,
      "description": "Only conversations waiting at least this long."
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50,
      "default": 20
    }
  },
  "additionalProperties": false
}

get_reply_guidelines

Permission: context:read · read only

The workspace's own instructions for replies (tone, sign-off, what to always or never say), its public details, and the titles of its knowledge documents. Read this before drafting so the reply sounds like the team rather than like an AI.

Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

get_customer_context

Permission: context:read · read only

Everything Apavin knows about one customer that an agent may see: profile, channels, recent email and WhatsApp conversations, open deals, team notes and remembered facts. Find the customer by contact_id, email or phone.

Input schema
{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "maxLength": 64
    },
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "phone": {
      "type": "string",
      "maxLength": 20
    }
  },
  "additionalProperties": false
}

search_customer_conversations

Permission: context:read · read only

Search customer conversations on the channels this agent can read (email and WhatsApp), by customer name or message text. Returns conversation ids per channel.

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 200
    },
    "channel": {
      "type": "string",
      "enum": [
        "email",
        "whatsapp",
        "any"
      ],
      "default": "any"
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50,
      "default": 20
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false
}

get_business_knowledge

Permission: context:read · read only

Find passages in the workspace's approved knowledge base (product information, prices, policies, FAQs uploaded to Apavin). Use this before stating a price, policy or product fact in a reply.

Input schema
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 300
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 8,
      "default": 4
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false
}

list_connected_accounts

Permission: any valid connection · read only

The email inboxes and WhatsApp numbers this agent can use, with their connection health. Credentials are never returned.

Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

get_action_permissions

Permission: any valid connection · read only

The permissions this connection has right now, and for each one that is unavailable, why: not granted to this client, switched off by the admin, not in the plan, or the member's role. Also states whether outbound messages need a person's approval.

Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

get_usage_summary

Permission: any valid connection · read only

Calls used and remaining this month, by tool. Failed and refused calls are listed but do not count against the allowance.

Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

get_recent_action_logs

Permission: audit:read · read only

Recent outbound actions requested through Apavin MCP and their outcomes: who asked, which account, approval status and result. Message bodies are not included.

Input schema
{
  "type": "object",
  "properties": {
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "default": 25
    },
    "status": {
      "type": "string",
      "enum": [
        "pending_approval",
        "executed",
        "failed",
        "denied",
        "cancelled",
        "any"
      ],
      "default": "any"
    }
  },
  "additionalProperties": false
}

add_customer_note

Permission: customers:write · writes to Apavin only

Write a note on the customer's record in Apavin, visible to the team: what they asked for, what was promised, what the team owes them. Stays inside Apavin; the customer never sees it.

Input schema
{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "note": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4000
    }
  },
  "required": [
    "contact_id",
    "note"
  ],
  "additionalProperties": false
}

create_follow_up_task

Permission: customers:write · writes to Apavin only

Create a task in Apavin for the team, such as "send the revised quote" or "call back after the demo", optionally tied to a customer and a due time. Assigned to the member who connected this agent. Nothing is sent to the customer.

Input schema
{
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "minLength": 3,
      "maxLength": 200
    },
    "details": {
      "type": "string",
      "maxLength": 4000
    },
    "contact_id": {
      "type": "string",
      "maxLength": 64
    },
    "due_at": {
      "type": "string",
      "format": "date-time",
      "description": "When it is due, ISO 8601 with offset."
    },
    "priority": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ],
      "default": "medium"
    }
  },
  "required": [
    "title"
  ],
  "additionalProperties": false
}

Resources: apavin://docs/tools, apavin://docs/safety, apavin://knowledge/&lbrace;id&rbrace;, template apavin://customers/&lbrace;contact_id&rbrace;. Prompts: morning_reply_round, draft_support_reply, email_follow_up, summarize_conversation.

Troubleshooting

  • 401 on every call. The token expired and the client did not refresh, or the connection was revoked. Reconnect.
  • The consent page says to ask an owner, admin or manager. Agents can read every conversation, so only roles that can already do that may connect one.
  • search_emails finds nothing old. Apavin reads mail synced since the account was connected, not the full mailbox history.
  • Templates fail with TEMPLATE_VALIDATION_UNAVAILABLE. Add the WhatsApp Business Account ID to the connection (MCP settings, Overview, or Settings, Channels).
  • Scheduled messages go out a few minutes late. The scheduler runs every ten minutes.

Security

See the security page for credential encryption, token handling, tenant isolation and what Apavin is not certified for.

Disconnect and revoke

In Settings, AI agents (MCP), Revoke access: revoke one connection or all. Tokens stop working immediately and queued, unsent messages are cancelled; the page reports how many of each. Clients can also call the revocation endpoint. To stop agents using an account, disconnect it in Settings, Channels, and delete the app password at your email provider.

Changelog and versioning

  • 1.1.0 (October 2026): reply queue, reply guidelines, customer notes and follow-up tasks (new customers:write scope), email drafts copied to the mailbox’s Drafts folder, morning reply round prompt.
  • 1.0.0 (October 2026): first release. 25 tools, OAuth 2.1, approvals, metering.

Tool names and required arguments do not change within a major version. New optional arguments and new tools may be added; the server’s serverInfo.version reports the version.