Tool reference

Chat tools

All 30 chat MCP tools with input shape, response shape, and example calls.

Thirty tools — the largest namespace — cover chatbot configuration, channels (including WhatsApp), live session handling, custom tools, analytics, and the audit log.

All endpoints follow the pattern POST https://mcp.vlozi.app/tools/chat.<name> with Authorization: Bearer ls_xxx. All responses use this envelope:

{ "data": <payload>, "error": null }   // success
{ "data": null,      "error": "..." }  // failure (with HTTP 4xx/5xx)

NOTE

bot_id is optional on almost every tool — omit it and Vlozi resolves your workspace's oldest bot (the "default bot", auto-created on first use if you have none). A workspace can have up to 10 bots.

Config

chat.list_bots

List your bots.

Scope: chatbot:config.read

Input: none

Response: { bots: { id, name, activeModel, memoryTier, archivedAt, createdAt, channelCount }[] }, oldest first (the first item is the default bot)


chat.create_bot

Create a new bot.

Scope: chatbot:config.write

Input: { name: string } (1–100 chars)

Response: { bot: BotConfig }

NOTE

Capped at 10 bots per workspace — returns 403 at the limit.


chat.delete_bot

Delete a bot and everything under it.

Scope: chatbot:config.write

Input: { bot_id: string } (required)

Response: { deleted: true }

CAUTION

Cascades explicitly through messages → tool calls → sessions → custom tools → channels → the bot itself. Irreversible. Returns 409 ("You can't delete your only bot") if it's the workspace's last one.


chat.get_config

Get a bot's full configuration.

Scope: chatbot:config.read

Input: { bot_id?: string }

Response: { config: BotConfig } — includes personaPrompt, fallbackMessage, handoffTrigger (default "[[HANDOFF]]"), activeModel, creativity, memoryTier, historyWindow, summaryEnabled/summaryDepth, tone, responseLength, language, crisisDetectionEnabled, knowledgeEnabled, leadCaptureRules, welcomeMessage, offlineMessage


chat.update_config

Update a bot's configuration. Pass only the fields to change.

Scope: chatbot:config.write

Input:

Field Type Notes
bot_id string
name string ≤100 chars
persona_prompt string ≤5000 chars
fallback_message string ≤500 chars
active_model "haiku" | "sonnet" | "opus"
creativity number 0–1
memory_tier number 0–4
history_window number 1–50
summary_enabled boolean
summary_depth "brief" | "detailed"
tone "formal" | "casual" | "friendly" | "professional"
response_length "brief" | "balanced" | "detailed"
language see note
crisis_detection_enabled boolean
knowledge_enabled boolean
welcome_message string ≤500 chars
offline_message string ≤500 chars
lead_capture_rules { trigger, askFor, message }[]

Response: { config: BotConfig } (full updated row)

NOTE

language accepts auto, en, hi, bn, ta, te, mr, gu, kn, ml, pa, ur, es, fr, ar, pt, de, zh. Every change is diffed and recorded in the audit log.

Channels

chat.list_channels

List connected channels.

Scope: chatbot:channels.read

Input: { bot_id?: string } — omit for every channel across the whole workspace (a different default than the config tools, which scope to one bot)

Response: { channels: { id, botId, platform, identifier, status, widgetToken, createdAt }[] }status is active | paused | auth_failed | rate_limited (the last two are set internally, not settable via any tool)


chat.add_channel

Connect a channel to a bot.

Scope: chatbot:channels.write

Input: { platform: "website_widget" | "whatsapp" | "telegram" | "instagram", identifier: string, credentials?: string, bot_token?: string, bot_id?: string } (platform/identifier required, identifier 1–500 chars)

Response: { channel: { id, platform, identifier, status: "active", widget_token?, embed_script? } }

NOTE

website_widget generates a widget_token and an embed_script <script> tag ready to paste into a page. telegram with a bot_token validates it against Telegram's API, renames identifier to the bot's @username, and registers a webhook (best-effort — failure to register still leaves the channel connected). Adding a channel is idempotent per (platform, identifier) — reconnecting the same messaging identity updates the existing row (fresh credentials, status: "active") instead of creating a duplicate. Use chat.connect_whatsapp for WhatsApp, not this tool.


chat.connect_whatsapp

Complete a WhatsApp Business connection via Meta's Embedded Signup flow.

Scope: chatbot:channels.write

Input: { code: string, phone_number_id: string, waba_id: string, bot_id?: string } (code/phone_number_id/waba_id required)

Response: { channel: { id, platform: "whatsapp", identifier: string, verified_name: string, status: "active", webhook_subscribed: boolean } }

NOTE

This is the callback step after Meta's Embedded Signup popup returns code/phone_number_id/waba_id to your frontend — there's no QR code involved. It exchanges the code for a long-lived token, validates the phone number, and subscribes the webhook (a failed webhook subscription is non-fatal — the channel connects anyway with webhook_subscribed: false).


chat.delete_channel

Disconnect a channel.

Scope: chatbot:channels.write

Input: { id: string } (required)

Response: { deleted: true }

NOTE

Sessions and messages already on this channel are untouched. For Telegram, this also best-effort tears down the registered webhook.


chat.set_channel_status

Pause or reactivate a channel.

Scope: chatbot:channels.write

Input: { id: string, status: "active" | "paused" } (both required)

Response: { updated: true, status: string }

Sessions

Sessions move ai_handled → human_escalated → closed (terminal — no reopen tool exists). assign_session/reply_to_session don't change status, just claim/answer the session.

chat.list_sessions

List sessions.

Scope: chatbot:sessions.read

Input: { bot_id?: string, status?: "ai_handled" | "human_escalated" | "closed" | "all", limit?: number, offset?: number } (status default all; limit 1–100 default 20)

Response: { sessions: { id, channelId, contactId, status, initiatedBy, assignedAgentId, messageCount, slaBreachAt, lastMessageAt, createdAt }[] }, newest message first


chat.get_session_messages

Get a session's transcript.

Scope: chatbot:sessions.read

Input: { session_id: string, limit?: number, before?: string } (session_id required; limit 1–100 default 50; before = a message id cursor)

Response: { messages: { id, role, content, intent, model, latencyMs, createdAt }[], has_more: boolean } — oldest to newest


chat.reply_to_session

Send a message as a human agent.

Scope: chatbot:sessions.write

Input: { session_id: string, content: string } (both required; content 1–4000 chars)

Response: { message: { id, role: "agent", content } }

NOTE

Self-assigns the session to you and clears its SLA timer — doesn't change status.


chat.assign_session

Assign a session to an agent.

Scope: chatbot:sessions.write

Input: { session_id: string, agent_id: string } (both required)

Response: { assigned: true, agent_id: string }

NOTE

No error on an unknown session — it's silently a no-op, matching the dashboard's own behavior.


chat.resolve_session

Close a session.

Scope: chatbot:sessions.write

Input: { session_id: string, summary?: string }

Response: { resolved: true }

NOTE

Terminal — sets status: "closed". If the session is linked to a contact, this also triggers Contact Intelligence to extract memories from the transcript in the background.


chat.escalate_session

Hand a session to a human.

Scope: chatbot:sessions.write

Input: { session_id: string, reason?: string } (session_id required)

Response: { escalated: true, status: "human_escalated" }

NOTE

Arms a 15-minute SLA timer. Unlike the other session-mutating tools, this one does not write an audit-log entry (only an internal event).


chat.summarize_session

AI-summarize a session's transcript.

Scope: chatbot:sessions.read

Input: { session_id: string } (required)

Response: { summary: string, creditsCharged: number }

IMPORTANT

Charges a flat 5-credit fee, refunded on failure. Always runs on the haiku model regardless of the bot's own configured active_model. Returns 422 if the session has no messages yet, 503 if no AI model key is configured.


chat.draft_reply

AI-draft the next agent reply — does not send it. Pair with reply_to_session.

Scope: chatbot:sessions.read

Input: { session_id: string, brief?: string } (brief = optional guidance on what to say)

Response: { reply: string, creditsCharged: number }

IMPORTANT

Charges a flat 5-credit fee, refunded on failure. Same model pinning and error conditions as summarize_session.

Custom tools

A "custom tool" is a tenant-registered webhook-backed function the bot's LLM can call mid-conversation — you provide a name, a JSON-Schema parameter spec, and a URL; Vlozi POSTs the arguments there and feeds the result back to the model.

chat.list_custom_tools

List a bot's custom tools.

Scope: chatbot:config.read

Input: { bot_id?: string }

Response: { tools: { id, name, description, parameters, webhook_url, has_auth: boolean, timeout_ms, enabled, created_at, updated_at }[] }

NOTE

has_auth reports whether an auth header is configured — the actual secret is never returned.


chat.list_tool_calls

List recent custom-tool invocations.

Scope: chatbot:config.read

Input: { bot_id?: string, tool?: string, session?: string, limit?: number, offset?: number } (limit 1–100 default 50)

Response: { calls: { id, sessionId, messageId, toolName, parameters, result, success, latencyMs, error, createdAt }[] }


chat.create_custom_tool

Register a new custom tool.

Scope: chatbot:config.write

Input:

Field Type Notes
name string (required) Lowercase snake_case, ≤64 chars
description string (required) 1–1000 chars — the LLM reads this to decide when to call it
parameters object (required) JSON Schema for the arguments
webhook_url string (required) Must be a public https URL
auth_header string Stored encrypted, sent as Authorization
timeout_ms number 100–30000, default 5000
enabled boolean Default true
bot_id string

Response: { tool: CustomToolDTO }

WARNING

webhook_url is rejected if it points at localhost, a private/internal IP range, or a cloud metadata endpoint — public https only. Returns 409 on a duplicate name within the same bot.


chat.update_custom_tool

Update a custom tool. Pass only the fields to change.

Scope: chatbot:config.write

Input: { id: string } plus any subset of create_custom_tool's fields

Response: { tool: CustomToolDTO }


chat.delete_custom_tool

Delete a custom tool.

Scope: chatbot:config.write

Input: { id: string } (required)

Response: { deleted: true }

Analytics

All six accept { bot_id?: string, days?: number } (days 1–365, default 30) and compute live from session/message data — nothing here is a stub.

chat.analytics_overview

Scope: chatbot:sessions.read

Response: { days, total_sessions, resolved, escalated, open, resolution_rate, escalation_rate, avg_messages_per_session, sla_breach_rate }


chat.analytics_intents

Scope: chatbot:sessions.read

Response: { intents: { intent, count }[] }, most common first


chat.analytics_models

Scope: chatbot:sessions.read

Response: { models: { model, count, avg_latency_ms, p95_latency_ms }[] }


chat.analytics_sessions_breakdown

Scope: chatbot:sessions.read

Response: { breakdown: { initiated_by, status, count }[] } — the full initiatedBy × status matrix


chat.analytics_tools

Scope: chatbot:sessions.read

Response: { tools: { tool_name, calls, success_rate, avg_latency_ms }[] }


chat.analytics_timeseries

Scope: chatbot:sessions.read

Response: { messages: { day, count }[], sessions: { day, count }[] } — two daily series, for sparklines

Audit

chat.get_audit_log

List config/session changes for a bot.

Scope: chatbot:config.read

Input: { bot_id?: string, action?: string, limit?: number, offset?: number } (limit 1–100 default 50)

Response: { entries: { id, botId, actorId, action, targetEntity, targetId, diff, createdAt }[] }

NOTE

action is one of bot_created, bot_deleted, bot_config_updated, channel_connected, channel_disconnected, channel_status_changed, session_assigned, session_resolved, tool_created, tool_updated, tool_deleted. Escalating a session does not appear here (see escalate_session above).

MCP · Tool referenceEdit on GitHub