Skip to main content
Glama
Moe03

Convocore MCP Server

by Moe03
README.md
# 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.

[![npm version](https://img.shields.io/npm/v/convocore-mcp.svg)](https://www.npmjs.com/package/convocore-mcp)
[![Docker Hub](https://img.shields.io/badge/docker-moe003%2Fconvocore--mcp-blue)](https://hub.docker.com/r/moe003/convocore-mcp)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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

B3.2/5.0

Scored across 145 tools

Disambiguation3/5

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.

Naming Consistency3/5

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.

Tool Count1/5

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.

Completeness4/5

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.

Maintenance

ActivityActive
ResponsivenessNo issues