Convocore MCP Server
# Convocore MCP Server
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that connects AI assistants (Claude Desktop, Cursor, and other MCP hosts) to the **Convocore** HTTP API. The host spawns this process, talks to it over **stdio** (standard input/output), and gains many tools for agents, conversations, knowledge bases (including mass URL ingest), and single-URL scraping.
[](https://www.npmjs.com/package/convocore-mcp)
[](https://hub.docker.com/r/moe003/convocore-mcp)
[](https://opensource.org/licenses/MIT)
---
## What this project is
| Piece | Role |
|--------|------|
| **MCP** | A protocol so clients (e.g. Claude) can list and call **tools** with structured arguments and get text (or other) results back. |
| **This server** | A small Node.js app using `@modelcontextprotocol/sdk`: it registers tools, validates arguments with **Zod**, and proxies calls to Convocore’s REST API with your **workspace bearer token**. |
| **Convocore API** | Backend at `https://{region}-api.vg-stuff.com/v3` (see [Regions](#api-regions-and-base-urls)). Your `WORKSPACE_SECRET` is sent as `Authorization: Bearer …`. |
This repository is **not** a chat UI. It is the **bridge** between an MCP-capable assistant and Convocore.
---
## What the server exposes (capabilities)
The server declares **tools only** (no MCP resources or prompts in code). Each successful tool call returns MCP **content** with a single **text** part whose body is **pretty-printed JSON** (`JSON.stringify(result, null, 2)`) from the Convocore API response.
| Area | Tools | Purpose |
|------|-------|---------|
| Agents | ~12 | CRUD, list, search, export/import, clone, usage, CSS, patch prompt |
| Conversations | ~12 | CRUD, list, export, assign, bulk/query, **channel send** |
| Knowledge base | ~14 | CRUD, patch, bulk get/create/delete, URL ingest, search, images, quota |
| Orgs / agency / clients | 6 | `orgs_read/write`, `agency_read/write`, `clients_read/write` |
| Leads CRM | 2 | `leads_read` / `leads_write` (list, export, import, magic import, …) |
| Agent HTTP tools | 5 | list/get/create/update/delete Convocore agent tools (not MCP tools) |
| Agent variables | 5 | list/get/create/update/delete agent variables |
| Channels | 4 | `get_agent_channels`, `create_channel_connect_link`, `get_connect_link_status`, `disconnect_meta_page` — connect WhatsApp / Messenger / Instagram through a no-login link |
| WhatsApp AI rules | 3 | `get_whatsapp_ai_rules`, `update_whatsapp_ai_rules`, `update_whatsapp_number_settings` — when the AI replies on WhatsApp |
| Campaigns | 2 | `campaigns_read` / `campaigns_write` — outbound call campaigns (create, edit, start/stop, restart, delete) |
| Call logs | 2 | `call_logs_read` / `call_logs_write` — list, get, export, create, edit, delete |
| Outbound calls & SMS | 4 | `get_agent_phone`, `start_outbound_call`, `send_sms`, `contact_leads` |
| Custom metrics | 2 | `custom_metrics_read` / `custom_metrics_write` — define metrics and read their data |
| Lead groups | 2 | `lead_groups_read` / `lead_groups_write` — list, create, assign, rename, delete |
| Folders | 2 | `folders_read` / `folders_write` — agent folders |
| Agent extras | 5 | `get_agent_audit_log`, `send_handoff_reminder`, `generate_conversation_summaries`, `agent_gallery_templates`, `notification_email` |
| WhatsApp management | 6 | `whatsapp_numbers_read/write`, `whatsapp_templates_read/write`, `whatsapp_campaigns_read/write` |
| Meta pages, SMS, email | 5 | `meta_pages_read`, `sms_numbers_read/write`, `email_channel_read/write` |
| Integrations | 3 | `integrations_read` / `integrations_write` / `integrations_test` — every connection (Google Calendar, Outlook Calendar, Google Sheets, Airtable, Shopify, Calendly, Zoho CRM, Gmail, Outlook mail, Zoho Mail, Google Drive), assign / update / remove on agents, diagnose an agent's setup, and inspect or run the agent's real integration tools |
| Zoho CRM records | 2 | `zoho_crm_records_read` / `zoho_crm_records_write` — list, search, COQL, get; create, update, upsert, delete, notes |
| Contacts | 2 | `contacts_read` / `contacts_write` — cross-channel identities |
| Agent backups | 2 | `agent_backups_read` / `agent_backups_write` — backup, restore, revert prompt, prompt caching |
| Code tools & sharing | 2 | `code_tools`, `tool_sharing` |
| Workspace | 3 | `workspace_read` / `workspace_write`, `generate_lead_funnel` |
| Testing | 3 | `test_agent_tool`, `test_agent_tool_request`, `run_agent_auto_test` |
| Discovery | 1 | `search_mcp_tools` — find the right tool without guessing |
| Scrape / embed / voice | many | scrape, embed code, voices, Twilio utils |
| Interact (WS) | 1 | Drive one agent turn; supports `toolTest` + `variablesOverrides` |
| Specs | 3 | UI Engine, channel integration, pricing |
---
### Light mode
The tools in the rows from "Campaigns" down to "Agent extras" (and every list tool) take `mode`:
- `compact` (default): every record and field, but long text is cut and bulky blobs (transcripts, page content, histories) are replaced by a size marker.
- `full`: the complete API response.
---
## How it runs (transport and lifecycle)
1. The **host** (Claude Desktop, Cursor, etc.) starts the server as a subprocess: e.g. `npx -y convocore-mcp`, `docker run …`, or `node dist/index.js`.
2. Communication uses **`StdioServerTransport`**: JSON-RPC messages on stdin/stdout. **Do not** write logs to stdout; the server logs to **stderr** (e.g. `Convocore MCP Server running on stdio`).
3. On startup, `getConfig()` reads env vars. If `WORKSPACE_SECRET` is missing, the process **throws** and exits.
4. The host sends `tools/list` and `tools/call`. Each call is validated, then `ConvocoreClient` performs `fetch()` to the REST API.
```mermaid
flowchart LR
Host[MCP host]
MCP[convocore-mcp stdio]
API[Convocore REST API v3]
Host <--> MCP
MCP --> API
```
---
## Repository layout
| Path | Purpose |
|------|---------|
| `src/index.ts` | MCP server, tool definitions (JSON Schema for hosts), Zod validation, tool dispatch |
| `src/convocore-client.ts` | HTTP client: paths, methods, query strings, JSON bodies |
| `src/agent-theme-palette.ts` | `hexToHsl` / `handleAutoGenPallet` — builds `nineColorPallet` for `customThemeJSONString` |
| `src/config.ts` | `WORKSPACE_SECRET`, `CONVOCORE_API_REGION`, optional `CONVOCORE_WORKSPACE_ID`, resolved `baseUrl` |
| `src/types.ts` | Shared TypeScript types for config and agent payloads |
| `dist/` | Compiled output (`pnpm run build` / `tsc`) — what npm publishes |
| `Dockerfile` | Multi-stage image: build with pnpm, run `node dist/index.js` (alternative distribution) |
| `docker-compose.yml` | Example service (see [Docker Compose note](#docker-compose)) |
| `claude_desktop_config.example.json` | Sample Claude Desktop MCP entry |
| `openapi.json` | OpenAPI spec (reference for API shape) |
---
## Environment variables
| Variable | Required | Default | Meaning |
|----------|----------|---------|---------|
| `WORKSPACE_SECRET` | **Yes** | — | Bearer token for the Convocore workspace (same as API key/secret from your dashboard). |
| `CONVOCORE_API_REGION` | No | `eu-gcp` | `eu-gcp` or `na-gcp`; selects API host (see below). |
| `CONVOCORE_API_BASE_URL` | No | — | Optional full REST base URL override. Useful for local dev, e.g. `http://localhost:5000/v3`. Overrides `CONVOCORE_API_REGION` when set. The `/interact` WebSocket URL is derived from this (scheme swapped to `ws/wss`, path replaced with `/interact`) unless `CONVOCORE_INTERACT_WS_URL` is also set. |
| `CONVOCORE_INTERACT_WS_URL` | No | — | Optional explicit override for **only** the `/interact` WebSocket URL, e.g. `ws://localhost:5000/interact`. Set this when you want REST traffic on prod but WebSocket traffic on a local debug server (or vice-versa). Used verbatim — supply scheme, host, port, and path. |
| `CONVOCORE_WORKSPACE_ID` | No | — | Workspace/org UUID (`agent.ownerID`). When set, MCP avoids heavy `GET /agents` scans used only to infer the workspace id. |
| `CONVOCORE_TELEMETRY` | No | on | Set to `0` to turn off anonymous usage telemetry. See [Telemetry](#telemetry). |
The server reads `WORKSPACE_SECRET`, `CONVOCORE_API_REGION`, optional `CONVOCORE_API_BASE_URL`, optional `CONVOCORE_INTERACT_WS_URL`, optional `CONVOCORE_WORKSPACE_ID`, and optional `CONVOCORE_TELEMETRY` / `CONVOCORE_TELEMETRY_DEBUG` / `DO_NOT_TRACK`. Any other variables in compose files or docs are ignored unless you wire them yourself.
### API regions and base URLs
| `CONVOCORE_API_REGION` | Base URL |
|------------------------|----------|
| `eu-gcp` | `https://eu-gcp-api.vg-stuff.com/v3` |
| `na-gcp` | `https://na-gcp-api.vg-stuff.com/v3` |
For local development, set `CONVOCORE_API_BASE_URL=http://localhost:5000/v3` to redirect both REST and WebSocket, or set `CONVOCORE_INTERACT_WS_URL=ws://localhost:5000/interact` to redirect only the `/interact` WebSocket while REST keeps using the regional host.
---
## Authentication
Every request from `ConvocoreClient` includes:
- `Authorization: Bearer <WORKSPACE_SECRET>`
- `Content-Type: application/json`
Non-OK responses: body is parsed as JSON; `message` is thrown as an error when present, otherwise a generic status message. Keep `WORKSPACE_SECRET` out of prompts, screenshots, and shared configs; use env vars or your host’s secret mechanism.
### Gray-label client connections
Agencies can let a whitelabel client connect Claude, ChatGPT or Cursor to **only the agents assigned to that client**, under the agency's brand, on a neutral host (`https://mcp-project.vg-stuff.com/mcp`, extra hosts via `GRAY_LABEL_MCP_HOSTS`).
- The agency turns on **AI assistant access** for the client (`mcpAccess` on the client). The client clicks **Connect AI** in their dashboard; the API mints a `gl_…` connection token stored as a hash on the agency workspace (`users/{workspaceId}/mcpClientConnections`).
- The agency host accepts `gl_` tokens only, and `gl_` tokens work only there. The API scopes every call to the client's agents (`client.widgetIDs ∪ org.widgetIDs`, read live) and refuses workspace-level routes; this server also narrows the tool list and checks agent ids.
- Server name, instructions, tool text, results, errors and the OAuth Connect page carry the agency brand (`{Agency} - {Client}`), never the platform's. Scope and brand refresh every minute on open sessions; revoking a connection or turning access off stops it.
---
## Quick start
### Prerequisites
- A Convocore **workspace secret** (`WORKSPACE_SECRET`).
- Optional: correct **region** (`eu-gcp` / `na-gcp`).
- **Node.js 20+** (ships with `npx`). Docker is optional and only needed for the container workflow.
### Option A: npx (recommended)
You don't have to install anything. Your MCP host (Claude Desktop, Cursor, etc.) runs the server on demand:
```bash
npx -y convocore-mcp
```
Set `WORKSPACE_SECRET` (and optionally `CONVOCORE_API_REGION`) in the host's `env` block — see the [Claude Desktop example](#claude-desktop) below.
The first invocation downloads the package (a few seconds); subsequent runs are cached by npm.
### Option B: Docker
```bash
docker run -i --rm \
-e WORKSPACE_SECRET="your_workspace_secret_here" \
-e CONVOCORE_API_REGION="eu-gcp" \
moe003/convocore-mcp:latest
```
`-i` keeps stdin open so the MCP host can speak JSON-RPC to the container.
### Option C: Local Node (development)
```bash
git clone https://github.com/moe003/convocore-mcp.git
cd convocore-mcp
pnpm install
pnpm run build
export WORKSPACE_SECRET="your_workspace_secret_here"
export CONVOCORE_API_REGION="eu-gcp"
node dist/index.js
```
---
## Connecting MCP hosts
### Claude Desktop
Config path:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
**npx (recommended):**
```json
{
"mcpServers": {
"convocore": {
"command": "npx",
"args": ["-y", "convocore-mcp"],
"env": {
"WORKSPACE_SECRET": "your_workspace_secret_here",
"CONVOCORE_API_REGION": "eu-gcp"
}
}
}
}
```
> **Windows note:** if Claude Desktop fails to spawn `npx` directly, wrap it with `cmd`:
>
> ```json
> {
> "mcpServers": {
> "convocore": {
> "command": "cmd",
> "args": ["/c", "npx", "-y", "convocore-mcp"],
> "env": {
> "WORKSPACE_SECRET": "your_workspace_secret_here",
> "CONVOCORE_API_REGION": "eu-gcp"
> }
> }
> }
> }
> ```
After saving the config, **fully quit and relaunch Claude Desktop**. The `convocore` server should appear in the MCP server list and the tools become available in chat.
**Docker (alternative):** pull the image first to avoid first-run timeout in the host:
```bash
docker pull moe003/convocore-mcp:latest
```
```json
{
"mcpServers": {
"convocore": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e", "WORKSPACE_SECRET=your_workspace_secret_here",
"-e", "CONVOCORE_API_REGION=eu-gcp",
"moe003/convocore-mcp:latest"
]
}
}
}
```
**Local Node (development):** use an absolute path to `dist/index.js`:
```json
{
"mcpServers": {
"convocore": {
"command": "node",
"args": ["/absolute/path/to/convocore-mcp/dist/index.js"],
"env": {
"WORKSPACE_SECRET": "your_workspace_secret_here",
"CONVOCORE_API_REGION": "eu-gcp"
}
}
}
}
```
### Cursor and other clients
Any client that supports **stdio** MCP servers can use the same `command` + `args` + `env` pattern as above. The recommended `command`/`args` is `npx` + `["-y", "convocore-mcp"]`; Docker and local Node also work. Set the same environment variables.
### Dashboard one-click install (hosted MCP)
For a workspace dashboard button, call the hosted helper with the MCP URL, region, and workspace secret:
```bash
curl -sS -X POST https://mcp.convocore.ai/v1/install-links \
-H 'Content-Type: application/json' \
-d '{
"mcpUrl": "https://mcp.convocore.ai/mcp",
"workspaceSecret": "vg_…",
"region": "na-gcp",
"workspaceName": "Acme Agency"
}'
```
Response highlights — connector / install `name` defaults to **`Convocore {workspaceName}`** (e.g. `Convocore Acme Agency`) for Claude, Cursor, and other hosts:
| Field | Use |
|-------|-----|
| `name` | Display name used in Claude `connectorName`, Cursor deeplink `name`, Claude Desktop key |
| `cursor.deeplink` | **Add to Cursor** — true one-click (`cursor://…/mcp/install` with URL + `Authorization` + `X-Convocore-Region` in base64 config) |
| `cursor.webFallback` | `https://cursor.com/en/install-mcp?…` if the protocol handler is not registered yet |
| `claude.installUrl` | **Add to Claude** — opens the official prefilled custom-connector modal |
| `claude.connectorUrl` | `/t/<base64url(secret)>/mcp?region=…` (path keeps the secret after Claude strips `?token=` from OAuth `resource`) |
| `claudeDesktop` | Optional local `mcp-remote` JSON for Claude Desktop config files |
**Why Claude needs `?token=` (and OAuth on the host)**
- Cursor deeplinks embed headers in base64 — secret travels with the install.
- Claude’s install URL only prefills **name + connector URL**. No header query params exist.
- Claude then runs **OAuth Dynamic Client Registration** against the MCP host. Without `/oauth/register` + authorize/token, you get *“Couldn't register with Convocore’s sign-in service”*.
- Hosted MCP implements that OAuth AS. Claude often strips `?token=` from OAuth `resource`, so the secret is in the **path** (`/t/…/mcp`). Authorize shows a one-click **Connect** page (auto-submits) — no paste. Access tokens **are** the workspace secret, `expires_in` ≈ **10 years**, plus refresh.
- MCP transport sessions idle-evict after ~**1 year** by default (`CONVOCORE_HOSTED_SESSION_IDLE_MS=0` disables eviction). Reconnect recreates a session with the same secret.
**Security note:** `?token=` in a Claude connector URL is a pragmatic tradeoff (logs/history). Prefer Cursor headers when possible; rotate the workspace secret if a link leaks.
You can also build the same URLs client-side with `buildInstallLinks` from `dist/install-links.js` without calling the API.
---
## HTTP API mapping (what each tool calls)
All paths are relative to `baseUrl` (e.g. `https://eu-gcp-api.vg-stuff.com/v3`).
| Tool | Method | Path / pattern |
|------|--------|----------------|
| `create_agent` | POST | `/agents` body `{ agent: { … } }` (legacy/raw mode) |
| `create_agent_from_template` | POST workflow | **Preferred**: explicit `systemPrompt` / branding / merged `voiceConfig`; optional `sourceUrl` scrape + KB; then `POST /agents`; response includes **full agent** via follow-up `get_agent` |
| `get_agent` | GET | `/agents/{agentId}` |
| `update_agent` | PATCH | `/agents/{agentId}` body `{ agent: { … } }` |
| `patch_agent_prompt` | GET+PATCH | `get_agent` then exact `old_string`→`new_string` on prompt/CSS field (Cursor StrReplace-style); PATCH only the changed fields |
| `delete_agent` | DELETE | `/agents/{agentId}` |
| `list_agents` | GET | `/agents` optional `?limit=` when supported |
| `search_agents` | GET | `/agents/search?workspaceId=…&page&limit&sortBy&starredOnly&search?` (workspace resolved internally from MCP config/workspace secret context) |
| `export_agent` | GET | `/agents/{agentId}/export-template` |
| `import_agent` | POST | `/agents/import-template` |
| `get_agent_usage` | POST | `/agents/{agentId}/usage` body `{ range }` |
| `list_conversations` | GET | `/agents/{agentId}/convos?limit&cursor` (cursor pagination; page>1 without cursor rejected) |
| `get_conversations_bulk` | GET×N | Fan-out `GET /agents/{agentId}/convos/{convoId}` (max 50 IDs, concurrency pool) |
| `query_conversations` | MCP | Cursor list + bulk filter (not server SQL; `maxScan` bound) |
| `get_agent_usage_bulk` | POST×N | Fan-out `POST /agents/{agentId}/usage` (max 20 agents) |
| `get_kb_docs_bulk` | GET×N | Fan-out `GET /agents/{agentId}/kb/{docId}` (max 30 docs) |
| `create_conversation` | POST | `/agents/{agentId}/convos` body `{ conversation }` |
| `get_conversation` | GET | `/agents/{agentId}/convos/{convoId}` |
| `update_conversation` | PATCH | `/agents/{agentId}/convos/{convoId}` body `{ conversation }` |
| `list_conversation_notes` | GET | `/agents/{agentId}/convos/{convoId}/notes` |
| `add_conversation_note` | POST | `/agents/{agentId}/convos/{convoId}/notes` body `{ text, authorName? }` |
| `update_conversation_note` | PATCH | `/agents/{agentId}/convos/{convoId}/notes/{noteId}` body `{ text, authorName? }` |
| `delete_conversation_note` | DELETE | `/agents/{agentId}/convos/{convoId}/notes/{noteId}` |
| `delete_conversation` | DELETE | `/agents/{agentId}/convos/{convoId}` |
| `export_all_conversations` | GET | `/agents/{agentId}/convos/export?format=&limit=&cursor=&…` (requires paid workspace / `hasEverPaid`) |
| `export_conversation` | GET | `/agents/{agentId}/convos/{convoId}/export?format=` |
| `assign_conversation` | POST | `/agents/{agentId}/convos/{convoId}/assign` body `{ assignToUserId, delegatedBy? }` |
| `create_kb_from_urls` | POST×N or 1 | Fan-out / batch `POST /agents/{agentId}/kb` with `sourceType=url` + `scrapeContent` |
| `create_kb_doc` | POST | `/agents/{agentId}/kb` body: KB fields |
| `list_kb_docs` | GET | `/agents/{agentId}/kb?page&pageSize` |
| `get_kb_doc` | GET | `/agents/{agentId}/kb/{docId}` |
| `update_kb_doc` | PATCH | `/agents/{agentId}/kb/{docId}` |
| `patch_kb_doc` | GET+PATCH | `get_kb_doc` then exact `old_string`→`new_string` on `content`/`name` (Cursor StrReplace-style) |
| `delete_kb_doc` | DELETE | `/agents/{agentId}/kb/{docId}` |
| `get_kb_stats` | GET | `/agents/{agentId}/kb/stats` |
| `scrape_url` | HTTP ping or crawler | `mode=check` (default): fast status for up to 20 URLs/images; `mode=scrape`: full page scrape (1 URL) |
| `interact_with_agent` | WSS | `wss://{region}-gcp-api.vg-stuff.com/interact` (single `InteractObject` in, streamed `ChunkMessage`s out) |
| `get_ui_engine_spec` | n/a | Static reference — does not hit the API |
---
## Tool reference (parameters and notes)
### Agent tools
**`create_agent_from_template`** — **Preferred for from-scratch chat+voice agents.** Workspace is resolved internally (no `workspaceId` input). Recommended explicit fields: `title`, `systemPrompt`, `voiceConfig` (must use `speechGen.provider` **`google-live`** or **`ultravox`** only — use **`search_voices`** on those providers), `primaryColor` (hex, from **`scrape_url`** colours when possible), `widgetImageUrl` (logo URL, e.g. favicon from **`scrape_url`**). Optional: `voicePrompt` (Gemini Live systemInstruction; omitted → reuse `systemPrompt`), `description`, **`themeType`** (`light`|`dark`, default `light`), **`sourceUrl`** (optional scrape wait + excerpt), `createKbUrlDoc` (**requires `sourceUrl`** when true), `defaultLanguage` (default `multilingual`), `proactiveMessage`, `branding`, `chatBgURL`, `additionalConfig`.
- Workflow for the AI: **`scrape_url`** first → pick colour + favicon URL → **`search_voices`** on `google-live` / `ultravox` for accents → then this tool with explicit prompts and full `voiceConfig`.
- MCP builds **`customThemeJSONString`** (`nineColorPallet`) from **`primaryColor`** (same lightness ramp as Convocore `handleAutoGenPallet`).
- After create, MCP calls **`get_agent`** and returns **`data.agent`** as the **full** document (plus `agentId`).
- Prefer env **`CONVOCORE_WORKSPACE_ID`** so MCP does not need to infer workspace from **`list_agents`**.
**`create_agent`** — Legacy direct mode for advanced/manual payload control. Required: `title`. Optional: `description`, `theme`, `disabled`, `light`, `enableVertex`, `autoOpenWidget`, `voiceConfig`, **`nodes`**, `additionalConfig`.
- Prefer `create_agent_from_template` unless you intentionally need low-level manual field control.
- **`nodes`:** Convocore’s multi-step graph; **`nodes[0].instructions`** is the **main system prompt**.
- **`additionalConfig`:** Plain object merged into the `agent` payload (same level as other fields). Use for fields not listed explicitly.
**`get_agent`** — Required: `agentId`. Response includes agent JSON; main prompt is under `nodes[0].instructions` when present.
**`update_agent`** — Required: `agentId`. Optional: same agent fields as create; patch semantics depend on API. To change the main prompt, update **`nodes[0].instructions`**. For large prompts prefer **`patch_agent_prompt`**.
**`patch_agent_prompt`** — Cursor-style surgical edit. Required: `agentId`, `old_string`, `new_string`. Optional: `replace_all`, `target` (`auto`|`nodes0`|`vg_instructions`|`vg_systemPrompt`|`proactiveMessage`|`customCSS` — vg_* still writes `nodes[0].instructions`), `sync_mirrors` (default **false**; never PATCHes `vg_instructions`). Fails if `old_string` is missing or ambiguous (unless `replace_all`).
**AI Funnel / lead scoring** — `funnelConfig` + `leadCollectionRules` on create/update, or `ownerNotifyEmails` on `create_agent_from_template`. Runtime emails sales on hot leads. Do **not** attach a custom HTTP “notify sales” webhook tool.
**`delete_agent`** — Required: `agentId`. Permanent deletion on the API side.
**`list_agents`** — Optional: `limit` (capped fetch when API supports `?limit=`). Prefer **`search_agents`** or **`CONVOCORE_WORKSPACE_ID`** for large workspaces instead of dumping every agent without a cap.
**`search_agents`** — Required: none. Optional: `search`, `page` (default 1), `limit` (default 50), `sortBy` (`newest` | `oldest` | `alphabetical`, default `newest`), `starredOnly` (default false). Workspace is resolved internally by MCP.
**`export_agent`** — Required: `agentId`. Returns template JSON for backup/migration.
**`import_agent`** — Required: `agentTemplate`, `agentName`. Optional: `fromAgentId`.
**`get_agent_usage`** — Required: `agentId`. Optional: `range: { from, to }` ISO date strings.
### Conversation tools
**`list_conversations`** — Required: `agentId`. Optional: `limit` (default 20, **max 20**), `cursor` (from previous `nextCursor`). Response: `data`, `hasMore`, `nextCursor`, `limit`. For page 2+ pass `cursor` — do **not** bump `page` alone (API rejects `page>1` without cursor). List reads the Postgres mirror; `summary` / `capturedVariables` are often missing on list rows.
**`get_conversations_bulk`** — Required: `agentId`, `convoIds` (1–50). Fan-out GETs; returns lean `{ ID, summary, ts, capturedVariables, userName, origin }` plus `failed[]`. Chunk larger audits.
**`query_conversations`** — Required: `agentId`. Optional filters: `origin`, `tsFrom`/`tsTo`, `capturedVariableExists`, `capturedVariableEquals`, `summaryContains`, `hasUserName`, plus `limit` / `maxScan`. MCP-side scan (not SQL).
**`get_agent_usage_bulk`** — Required: `agentIds` (1–20). Optional shared `range`.
**`get_kb_docs_bulk`** — Required: `agentId`, `docIds` (1–30). Optional `includeContent` (default false).
**`create_conversation`** — Required: `agentId`, `conversation`. The API expects at least a **`ts`** (timestamp) in the conversation object; you may add `userName`, `userEmail`, etc. per your Convocore setup.
**`get_conversation`** — Required: `agentId`, `convoId`.
**`update_conversation`** — Required: `agentId`, `convoId`, `conversation` (partial fields).
**Conversation notes** — a timeline of human review notes per conversation (`reviewNotes`, oldest first; also returned by `get_conversation`). `add_conversation_note` / `update_conversation_note` / `delete_conversation_note` need `agentId`, `convoId`, `text` / `noteId`; `authorName` (optional) labels an API-key caller such as "Claude via MCP". Notes cannot be changed through `update_conversation`. Every change is recorded in the workspace Logs (who, IP, time). `query_conversations` accepts `hasNotes` and `noteContains`.
**`delete_conversation`** — Required: `agentId`, `convoId`.
**`export_all_conversations`** — Required: `agentId`. Optional: `format` (`json`|`csv`), `limit`, `sort`, `fromTs`, `toTs`, `cursor`, `convoIds`. Requires a **paid workspace** (`hasEverPaid === true`); billed against monthly export quota. Cursor pagination via `nextCursor` / `hasMore`.
**`export_conversation`** — Required: `agentId`, `convoId`. Optional: `format` — `json` or `csv`. Requires a **paid workspace** (`hasEverPaid === true`).
**`assign_conversation`** — Required: `agentId`, `convoId`, `assignToUserId`. Optional: `delegatedBy`.
### Knowledge base tools
Tool descriptions in code note **“VG agents only”** — KB operations target `/agents/{id}/kb` and may only apply to supported agent types on the Convocore side.
**`create_kb_from_urls`** — **Preferred for many pages.** Required: `agentId`, `urls` (max **50**). Optional: `mode` (`per_url` default | `batch`), `name`, `tags`, `refreshRate` (`3d`|`7d`|`never`), `scrapeContent` (default true), `skipExisting` (default true). Uses the KB router to scrape — do **not** pre-scrape with `scrape_url` / web fetch. Scraping is async; poll `list_kb_docs` / `get_kb_doc`.
**`create_kb_doc`** — Required: `agentId`, `name`, `sourceType`: `doc` | `url` | `sitemap`.
- **`doc`:** use `content` for text.
- **`url`:** use `urls` (array), optional `scrapeContent`.
- **`sitemap`:** use `sitemapUrl`, optional `maxPages`.
Optional: `metadata`, `tags`, `refreshRate` — `3d` | `7d` | `never` (default `never`; matches Convocore API).
**`list_kb_docs`** — Required: `agentId`. Optional: `page` (default 1), `pageSize` (default 20).
**`get_kb_doc`** — Required: `agentId`, `docId`.
**`update_kb_doc`** — Required: `agentId`, `docId`. Optional: `name`, `content`, `metadata`, `tags`, `refreshRate`, `url`. For large bodies prefer **`patch_kb_doc`**.
**`patch_kb_doc`** — Cursor-style surgical edit. Required: `agentId`, `docId`, `old_string`, `new_string`. Optional: `replace_all`, `field` (`content`|`name`, default `content`).
**`delete_kb_doc`** — Required: `agentId`, `docId`.
**`get_kb_stats`** — Required: `agentId`.
### Scrape tool
**`scrape_url`** — Provide `url` and/or `urls` (max **20**).
- **`mode: "check"` (default):** fast HTTP ping — status (200/404/…), `ok`, content-type, final URL after redirects. Use to verify images, logos, and page links before wiring them into an agent.
- **`mode: "scrape"`:** full Convocore crawler scrape of **one** URL (waits up to ~120s) for text/colours/favicon. Workspace resolved internally. Not for KB ingest (`create_kb_from_urls`).
### Interact (WebSocket) tool
`interact_with_agent` is the only WebSocket-backed tool. It opens a single connection to `wss://{region}-gcp-api.vg-stuff.com/interact`, sends one `InteractObject`, and aggregates every streamed `ChunkMessage` (`chunk` / `debug` / `action` / `metadata` / `sync_chat_history`) into one MCP response. Authentication uses the same `Authorization: Bearer <WORKSPACE_SECRET>` header as REST.
**Required:** `agentId`, `convoId`.
**Common optional:**
- `prompt` — User message. Special values: `"start"` (initial greeting), `"@cancel:<reason>"`, `"@rewind:<nodeId>"` (v2/node agents).
- `bucket` — `voiceglow-eu` or `(default)`. Auto-derived from `CONVOCORE_API_REGION` (eu-gcp → `voiceglow-eu`, na-gcp → `(default)`); only override to deliberately cross regions.
- `messageType` + `visualPayload` — for image turns.
- `replyTo` — reply context for a previous message.
- `lightConvoData` — `userName`, `userEmail`, `userPhone`, `origin`, `capturedVariables`, etc. Surfaced into the agent's system prompt where supported.
- `agentData` / `workspaceData` / `turnsHistory` — overrides that skip Firestore loads.
- `disableUiEngine`, `disableRecordHistory`, `v2`, `isTest`, `isLLMStudio`, `kbPreview`, `agentProfileId`, `toolTest`, `formSubmissionMetadata`, `initNodesOptions` — same flags as the underlying `EWSInteractModel`.
- `timeoutMs` (default `120000`, max `600000`) — how long the MCP waits for the streamed turn before forcing the WebSocket closed.
- `raw` (default `false`) — when true, the response includes every raw streamed chunk; when false, only the aggregated text + actions + metadata + final turns are returned (cheaper on tokens).
**Response shape (default `raw: false`):**
```json
{
"assistantText": "...",
"uiEngineEnabled": false,
"uiEngineSnapshot": null,
"uiEngineSummary": [],
"actions": [],
"metadata": { "inputTokens": 0, "outputTokens": 0, "llmUsed": "...", "sources": [], "turns": [] },
"turns": [],
"closeCode": 1000,
"closeReason": "",
"durationMs": 1234,
"timedOut": false,
"chunkCount": 17
}
```
#### UI Engine handling
When the agent has `vg_enableUIEngine: true` (and the request did not pass `disableUiEngine: true`), the server streams **JSON-stringified `TurnProps` snapshots** instead of plain text. UI Engine snapshots are **overwriting** (each chunk is a full snapshot of the bot turn so far) — `interact_with_agent` parses them, keeps only the **latest** snapshot as `uiEngineSnapshot`, and produces a compact `uiEngineSummary` for quick scanning:
```json
{
"assistantText": "",
"uiEngineEnabled": true,
"uiEngineSnapshot": {
"from": "bot",
"ts": 1719931200,
"messages": [
{ "from": "bot", "type": "text", "item": { "type": "text", "payload": { "message": "Pick one:" } } },
{ "from": "bot", "type": "choice", "item": { "type": "choice", "payload": { "buttons": [ { "name": "Pricing", "request": { "type": "text", "payload": { "message": "Tell me about pricing" } } } ] } } }
]
},
"uiEngineSummary": [
{ "index": 0, "type": "text", "summary": "Pick one:", "webChannelOnly": false },
{ "index": 1, "type": "choice", "summary": "1 button: Pricing", "webChannelOnly": false }
],
"...": "..."
}
```
The eight UI Engine message types are `text`, `choice`, `visual`, `cardV2`, `carousel`, `iFrame`, `form`, `input`. **`form` and `input` are emitted only on web channels** (`web-chat` / `text` origin). Call **`get_ui_engine_spec`** before testing or building UI-Engine-enabled agents to load the full schema.
> **Cost note:** every call runs a real agent turn (LLM + voice + tools) and consumes Convocore credits exactly like a normal chat. It is not a dry-run.
### UI Engine spec tool
**`get_ui_engine_spec`** — Returns the full Convocore UI Engine schema. Static knowledge, no API call, no credits.
- Required: none.
- Optional: `section` — `"all"` (default) | `"meta"` | `"envelopes"` | `"message_types"` | `"shared"` | `"rules"` | `"checklist"` | `"primer"`.
- Optional: `messageType` — `"text" | "choice" | "visual" | "cardV2" | "carousel" | "iFrame" | "form" | "input"`. When set, returns just that message-type schema (overrides `section`).
Use this BEFORE:
1. Validating output from `interact_with_agent` against a UI-Engine-enabled agent.
2. Creating / updating an agent whose system prompt should teach the model to emit UI Engine messages — bake the relevant rules and `messageType` shapes into `nodes[0].instructions`.
---
## Convocore concepts: nodes and prompts
- Each **node** can represent a step in a workflow.
- The **first node** (`nodes[0]`) holds the **primary instructions** (`instructions` field) that define default agent behavior.
- **`light` mode** (agent flag): described in-tool as no chat history retention for privacy.
---
## Errors and validation
- **Invalid tool arguments:** Zod validation fails → error with `Invalid arguments: …`.
- **Unknown tool name:** thrown as `Unknown tool: …`.
- **API errors:** thrown with the message from the JSON body when available.
- **Startup:** missing `WORKSPACE_SECRET` → configuration error before the server connects.
---
## Natural language examples (for end users)
After configuration, users can ask their assistant things like:
- “List all my Convocore agents” → `list_agents`
- “Create an agent for this website from scratch” → `create_agent_from_template` (preferred default)
- “Export all conversations for agent … as CSV” → `export_all_conversations`
- “Add many hotel/site pages to the KB” → `create_kb_from_urls` (KB router scrapes; do not web-fetch first)
- “Add one URL / sitemap to the KB” → `create_kb_doc` with `sourceType: url|sitemap` + `scrapeContent: true`
- “Are these image/page links dead?” → `scrape_url` with `mode: "check"` + `urls: [...]`
- “Scrape one URL for branding (colours/favicon)” → `scrape_url` with `mode: "scrape"`
Exact tool choice and arguments are up to the host model; the **tool descriptions** in `src/index.ts` are what the model sees.
---
## Docker
```bash
docker pull moe003/convocore-mcp:latest
```
Common tags (see Docker Hub for current list): `latest`, version tags such as `2.0.0` / `1.0.x` as published by the maintainer.
Build locally:
```bash
docker build -t moe003/convocore-mcp:latest .
```
### Docker Compose
The included `docker-compose.yml` runs the image with **stdin open** for MCP-style use. Set `WORKSPACE_SECRET` and optionally `CONVOCORE_API_REGION` in your environment or an `.env` file beside the compose file. Authentication is **`WORKSPACE_SECRET` only** (no separate API key variable is read by the server).
---
## Development
| Command | Action |
|---------|--------|
| `pnpm install` | Install dependencies |
| `pnpm run build` | Run `tsc` → `dist/` and chmod the bin |
| `pnpm run dev` | `tsc --watch` |
Dependencies: `@modelcontextprotocol/sdk`, `zod`, plus file-reader stack (`mammoth`, `pdf-parse`, `xlsx`, `sharp`, `mime-types`). Dev: `typescript`, `@types/node`, `shx`.
### Publish to npm (maintainers)
```bash
pnpm install
pnpm run build
pnpm pack --dry-run # sanity check the tarball
pnpm publish --access public
```
`prepublishOnly` re-runs the build automatically. Only `dist/`, `README.md`, and `LICENSE` are shipped (controlled by the `files` field in `package.json`).
### Push Docker image (maintainers)
```bash
docker push moe003/convocore-mcp:latest
```
---
## Telemetry
Like Next.js, convocore-mcp collects anonymous usage data to learn which tools are used and where they fail. It is **on by default**.
**What is sent, per tool call:** the tool name, whether it succeeded, a short error category (e.g. `input_validation_error`) plus, for failures only, a short error message with emails, URLs, IDs and numbers removed, the `action` of action-based tools (e.g. `assign_to_agent`), how long it took, the MCP client name and version (e.g. Claude Desktop, Cursor), the convocore-mcp version, Node.js version, OS platform, and a random id for the current server process.
**What is never sent:** tool arguments, tool results, prompts, agent content, contacts, conversations, or any file contents.
Events are batched and sent to the Convocore API in your own region (`<base URL>/mcp/telemetry`), authenticated with your workspace secret, so they are tied to your workspace and nothing else. Sending happens in the background and never slows down or fails a tool call.
**Opt out** by setting either variable in your MCP config's `env`:
```json
"env": {
"WORKSPACE_SECRET": "...",
"CONVOCORE_TELEMETRY": "0"
}
```
`DO_NOT_TRACK=1` is respected too. To see exactly what would be sent without sending anything, set `CONVOCORE_TELEMETRY_DEBUG=1`; events are printed to stderr.
The hosted server at `mcp.convocore.ai` runs on Convocore infrastructure and records the same events.
---
## Contributing and license
Contributions are welcome via pull request.
MIT License — see the `LICENSE` file.
---
## Links
- [Convocore API / product docs](https://convocore.ai/docs)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [npm — convocore-mcp](https://www.npmjs.com/package/convocore-mcp)
- [Docker Hub — moe003/convocore-mcp](https://hub.docker.com/r/moe003/convocore-mcp)
- [Issues](https://github.com/moe003/convocore-mcp/issues)
- [Convocore support](https://convocore.ai/support)
---
Built for the Convocore community.
TDQS
Scored across 145 tools
The descriptions are unusually explicit and often cross-reference the correct alternative, which helps distinguish many tools. However, the set contains several overlapping families: five ways to create an agent, many conversation retrieval/query/export tools, multiple KB ingestion tools, and duplicated usage/credit reporting paths. These overlaps make misselection likely at 145 tools even though the boundaries are documented.
Most names are readable snake_case, but the server mixes several conventions: verb_noun CRUD (list_agents, create_kb_doc, delete_conversation) with resource_read/resource_write action buckets (orgs_read, leads_write, campaigns_read) and noun-only tools like code_tools and tool_sharing. The patterns are systematic by domain, but they are not uniform across the whole tool set.
At 145 tools, the surface is far beyond a well-scoped 3-15 tool range and well into the extreme 50+ category. While Convocore is a broad platform, the sheer number of tools creates a heavy selection and maintenance burden.
The server covers lifecycle operations across agents, conversations, knowledge base, channels, integrations, CRM, campaigns, usage, and workspace settings. There are minor gaps, such as voice phone-number assignment largely being dashboard-only and domain verification being dashboard-only, but most core workflows have create/read/update/delete coverage.