ChatbotX

io.chatbotxPublished by chatbotx.ioOfficial publisherv1.8.1Updated Nov 6, 2026

Omnichannel customer messaging, CRM contacts, flows, sequences, broadcasts, and AI automation.

Overview

AI-generated overview

ChatbotX MCP connects an assistant to a ChatbotX workspace to manage contacts, conversations, flows, broadcasts, sequences and AI agents.

What you can do
  • Discover workspace capabilities, token scopes and the flow-spec schema
  • Manage contacts: create, look up, tag, set custom fields, send messages or flows, subscribe to sequences
  • Handle conversations and messages: list, read, assign to users or inbox teams
  • Work with flows, broadcasts, sequences, keywords, pipelines and mini apps
  • Create and update AI agents and list AI files and functions
  • Read analytics and error logs, and search the wider API for other operations
When to use it
Useful when an assistant should operate a ChatbotX customer messaging workspace: answering questions about contacts and conversations, drafting or publishing flows, sending messages, or pulling broadcast and flow analytics without switching tools.
Requirements
Remote endpoint at app.chatbotx.io over Streamable HTTP or SSE, with OAuth 2.1 sign-in and workspace consent; only workspace owners and superAdmin members can authorize. A local stdio option exists via the npm package, needing Node.js 24 or newer, CHATBOTX_API_URL and a workspace token in CHATBOTX_API_KEY.
Before you install
Tokens act on the whole consented workspace, and switching workspaces requires reconnecting. Mutating operations need explicit approval and a repeat call with _confirm, which is a guardrail rather than an authorization boundary. Messages, flows and broadcasts can be sent to real contacts. A one-time secret token returned by connections_create is shown only once. Legacy setups may pass the workspace token in a URL query string.

Installation

In SourceWeft

  1. Open ChatbotX in the dashboard and add it to a workspace.
  2. Connect the required credentials. They are stored privately and never shown on public pages.
  3. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.chatbotx%2Fmcp/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config. The client completes OAuth sign-in on first connect.

{
  "mcpServers": {
    "chatbotx": {
      "type": "http",
      "url": "https://app.chatbotx.io/mcp/messages"
    }
  }
}

README

ChatbotX MCP Server

Model Context Protocol server for ChatbotX. Gives AI agents (Claude, Cursor, ChatGPT, etc.) access to your ChatbotX workspace through tools that are automatically generated from the ChatbotX OpenAPI spec — no manual tool definitions needed.

Published skill/agent distribution docs live in the separate chatbotx-agent package; this repo owns the MCP server implementation and README.

How it works

On startup the server fetches {CHATBOTX_API_URL}/public-spec.json and registers one MCP tool per API operation the spec marks x-mcp.visibility: "default". CHATBOTX_API_URL is the origin including the /api path prefix (e.g. https://app.chatbotx.io/api). Adding a new default-visible API endpoint in ChatbotX automatically makes it available as a tool — the spec is re-fetched in the background whenever it's older than CHATBOTX_SPEC_TTL_MS (default 5 minutes), so a new/changed operation shows up on the next tools/list call without a server restart.

OAuth 2.1

Remote MCP clients should authenticate through OAuth 2.1. The production endpoints are https://app.chatbotx.io/mcp/messages for Streamable HTTP and https://app.chatbotx.io/mcp/sse for legacy SSE — the same URL for every account, so it works as a Claude or ChatGPT marketplace connector. The user picks the target workspace on the consent screen, and every token the client holds acts on that workspace; to switch, disconnect and connect again. Only workspace owners and superAdmin members can authorize. An explicit ?workspace_id=<id> (or x-workspace-id header) may select a workspace only for legacy connections that predate the picker. A different workspace than the one consented for a new connection is rejected; disconnect and connect again to switch. The builder settings block Settings → Integrations → ChatbotX MCP provides the exact connection URL and lets each user revoke their OAuth grants.

Legacy workspace tokens remain supported for stdio and existing connections.

Default tools vs. the full API

ChatbotX's public API has ~350 operations. Listing all of them as MCP tools overwhelms an agent's context and its ability to pick the right one, so tools/list returns only a curated default set (see below) plus three meta-tools:

ToolDescription
search_toolsSearch the full API for a tool not in the default set. Returns { matches, hint? }, where each match has its name, description, and input schema.
call_toolExecute any tool by name, including ones search_tools found but tools/list doesn't show.
get_guideRead an operational safety guide when a workflow involves approvals, flows, inbox handover, contacts, or pipelines.

Use search_tools when the task needs something outside the default set (e.g. deleting a resource, managing AI agents, coupons, products) — then invoke it with call_tool.

search_tools's catalog (tool names, summaries, descriptions) is entirely English. The calling client must translate the user's intent into an English "action + resource" query before searching; the ranker does not translate. When an accented Latin or non-Latin query reaches the server, search_tools returns a hint asking the client to translate and retry in English.

  • Name normalization: a dotted or camelCase operation label (contacts.get, contactsGet) is accepted and re-derived to the executable snake_case name — you don't have to pass the exact string search_tools returned.
  • Unknown-tool suggestions: an unrecognized name returns the closest matching tool names instead of a bare error, so a model can self-correct without another search_tools round trip.
  • Pre-flight argument check: a call_tool invocation missing a field the selected tool's inputSchema marks required is rejected immediately with the missing field names, instead of waiting for the real API's 422. A common wrapper mistake (nesting every field under body/params/input instead of passing them at the top level) is called out explicitly.
  • Contact identifier auto-prefix: a bare email, +-prefixed or local 0-prefixed phone number, or numeric id passed as identifier to a contact tool is automatically prefixed (email:/phone:/id:) before the request is sent, matching what the API actually requires.

Human approval

Every operation carries an x-mcp.hitlPolicy from the public OpenAPI spec; reads use none. Mutating operations return CONFIRMATION_REQUIRED with the policy, proposed arguments, and current state when available; show that response to the user, then repeat the same call with _confirm: true only after explicit approval. _confirm is a compatibility guardrail, not an authorization boundary.

Writes that are read-only computations declare hitlPolicy: "none" in the backend. Destructive writes also carry the MCP destructiveHint annotation. When a current-state read fails for any reason, currentState is omitted and currentStateUnavailable explains why; the failed read never blocks confirmation.

Every tools/list definition also includes a human-readable title and explicit readOnlyHint, destructiveHint, idempotentHint, and openWorldHint annotations. Dynamic tool titles come from the OpenAPI operation summary. The loader marks confirm_outbound operations as open-world by default; an x-mcp.openWorldHint override takes precedence.

Scope-based filtering

tools/list is further narrowed to what the calling token can actually use, resolved once per token via GET /v1/token (introspectToken, cached per token value for CHATBOTX_SPEC_TTL_MS):

  • A token missing a scope never sees that scope's tools (they still exist for search_tools/call_tool, which always hit the real API and get a real 403 if unauthorized).
  • A read_only token only sees tools whose readOnlyHint annotation is true — every GET by default, plus any POST explicitly marked x-mcp.readOnlyHint: true for an endpoint that reads without writing (no default tool currently uses this).
  • capabilities_get and token_get are always visible regardless of scope — an agent needs them to discover what it can do and what its token allows before anything else works.
  • If token introspection itself fails (network blip, unreachable API), filtering fails open — tools/list falls back to the full default set. The actual API call still enforces the token's real permissions either way.

Discovery tools an agent should call first

ToolDescription
capabilities_getDiscover workspace entities and query channel before authoring a channel-bound FlowSpec to receive its supported blocks and limits.
token_getGet the calling token's workspace id, permission (read_only/full), and scopes — check before attempting a write.
schemas_flow_specGet the JSON Schema for the spec object flows_publish/flows_update_draft/flows_validate accept — the authoritative reference for every flow step type.

Available tools

Tool names are derived from the OpenAPI operationId converted to snake_case (e.g. tags.list → tags_list). The current default set has 52 tools:

Capabilities

ToolDescription
capabilities_getDiscover workspace entities and a requested channel's FlowSpec policy
schemas_flow_specGet JSON Schema for flow-spec DSL
token_getGet calling token workspace id, permission, and scopes

AI Agents

ToolDescription
ai_agents_listList AI agents
ai_agents_createCreate AI agent
ai_agents_updateUpdate AI agent
ai_files_listList AI files
ai_functions_listList AI functions

Analytics

ToolDescription
analytics_new_contact_counts_per_dayGet new contact counts per day
analytics_blocked_contacts_per_dayGet blocked contacts per day
analytics_flow_statsGet flow analytics
analytics_broadcast_statsGet broadcast stats
analytics_sequence_step_statsGet sequence step stats

Broadcasts

ToolDescription
broadcasts_listList broadcasts
broadcasts_getGet broadcast
broadcasts_stopStop broadcast

Connections

ToolDescription
connections_createConnect channel or integration
connection_providers_listList connection providers
connect_sessions_getGet connect session

For connections_create with provider: "api", the response includes a one-time secret.token. Store it before discarding the response; it is never retrievable again.

Contacts

ToolDescription
contacts_createCreate contact
contacts_getGet contact by identifier (id:123, email:[email protected], phone:+84...)
contacts_listList contacts
contacts_list_tagsGet all tags added to contact
contacts_add_tags_by_nameAdd tags to contact by name
contacts_list_custom_fieldsGet all custom fields from contact
contacts_set_custom_fieldSet contact custom field value
contacts_list_messagesList messages for contact
contacts_send_messageSend message to contact
contacts_send_flowSend flow to contact
contacts_list_sequencesList contact sequence subscriptions
contacts_subscribe_sequencesSubscribe contact to sequences

Conversations

ToolDescription
conversations_listList conversations
conversations_getGet conversation
conversations_assignAssign or unassign conversation to user or inbox team

Error Logs

ToolDescription
error_logs_listList error logs

Flows

ToolDescription
flows_listList flows
flows_getGet flow
flows_createCreate flow
flows_update_draftUpdate flow draft
flows_publishPublish flow
flows_validateCompile and validate flow spec without publishing

Keywords

ToolDescription
keywords_listList keywords (automated responses)

Messages

ToolDescription
messages_listList messages on conversation

Mini Apps

ToolDescription
mini_apps_listList Mini Apps
mini_apps_createCreate Mini App

Pipelines

ToolDescription
pipelines_listList pipelines
pipelines_list_itemsList pipeline items
pipelines_create_itemCreate pipeline item
pipelines_move_itemMove item to stage

Sequences

ToolDescription
sequences_listList sequences
sequences_getGet sequence
sequences_updateUpdate sequence name or active state

Everything else — deletes, less-common resources (coupons, products, webhooks, saved replies, tags/triggers/inboxes/custom-fields management, workspace members, etc.), connection lifecycle management beyond the initial connect (disconnect, reconnect, refresh, verify, rename) — is reachable via search_tools → call_tool, not tools/list.

Operations whose security names no workspace-token scheme are not tools at all — isWorkspaceTokenOperation (src/openapi-loader.ts) drops them, so neither tools/list nor search_tools returns them. That covers deprecated operations, channel-token operations (/v1/channels/api/*), and the mobile-app-only member surface (/v1/me*, /v1/realtime/connect-token, marked by MOBILE_APP_TOKEN_ONLY_PATHS in apps/builder/src/lib/orpc/public-spec.ts): an MCP OAuth or workspace token has no member identity and would always get 401.

conversations_list accepts view: "compact" to drop ad attribution and thread-control metadata from each conversation's contact inboxes (default full); flows_list accepts enableInInbox: true to return only flows that can be started from the inbox.

Prerequisites

  • Node.js >= 24
  • A workspace token only for the stdio and workspace-token connection options.

Quick start

Option A — OAuth (recommended, remote)

Use the builder-hosted MCP endpoint. The client opens a browser for sign-in and consent; no workspace token belongs in the client configuration.

Claude Code:

bash
claude mcp add chatbotx -t http -s user \  "https://app.chatbotx.io/mcp/messages"

Claude Desktop / Cursor:

json
{  "mcpServers": {    "chatbotx": {      "type": "http",      "url": "https://app.chatbotx.io/mcp/messages"    }  }}

ChatGPT: add https://app.chatbotx.io/mcp/sse as a custom connector. ChatGPT completes OAuth in the browser.

The load balancer must forward /mcp/* to the MCP server without stripping the /mcp prefix. The builder serves protected-resource discovery under /.well-known/oauth-protected-resource/mcp/*.

Option B — stdio (workspace token, local use)

Claude spawns the server process on demand. No server needs to be running. The workspace token is supplied via CHATBOTX_API_KEY.

The package is published to npm as chatbotx-mcp — npx -y chatbotx-mcp fetches and runs it with no local checkout or build required. Use a local node /path/to/dist/index.mjs instead when developing against this repo.

Claude Code CLI:

bash
claude mcp add chatbotx \  -e CHATBOTX_API_KEY=<your-token> \  -e CHATBOTX_API_URL=https://your-instance.com/api \  -e CHATBOTX_MCP_TRANSPORT=stdio \  -s user \  -- npx -y chatbotx-mcp

Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

json
{  "mcpServers": {    "chatbotx": {      "command": "npx",      "args": ["-y", "chatbotx-mcp"],      "env": {        "CHATBOTX_API_KEY": "<your-token>",        "CHATBOTX_API_URL": "https://your-instance.com/api",        "CHATBOTX_MCP_TRANSPORT": "stdio"      }    }  }}

Running from a local checkout instead (e.g. node /path/to/dist/index.mjs) works the same way — swap command/args accordingly.

Option C — SSE (workspace token, shared / remote access)

Run the server once and multiple clients connect via URL. Pass the workspace token in the request header.

bash
# Start the serverpnpm start
# Add to Claude Code CLIclaude mcp add chatbotx \  -t sse \  -H "x-workspace-token: <your-token>" \  -s user \  "https://your-mcp-server.com/sse"

Claude Desktop:

json
{  "mcpServers": {    "chatbotx": {      "type": "sse",      "url": "https://your-mcp-server.com/sse",      "headers": {        "x-workspace-token": "<your-token>"      }    }  }}

Option D — ChatGPT.com (workspace-token SSE)

ChatGPT.com connects via SSE. The server must be publicly reachable. Because ChatGPT does not support custom request headers, pass the workspace token directly in the URL:

  1. Start the server with CHATBOTX_MCP_TRANSPORT=sse (or both).
  2. In ChatGPT Settings → Connectors → Add custom connector, set the URL:
    https://your-mcp-server.com/sse?workspace_token=<your-token>
    When using this URL in a shell command, always quote it to prevent ? being interpreted as a glob:
    bash
    claude mcp add chatbotx -t sse -s user "https://your-mcp-server.com/sse?workspace_token=<your-token>"
  3. Set CHATBOTX_MCP_SERVER_INSTRUCTIONS so ChatGPT uses tools instead of its training data. Leave it unset unless replacing the full built-in workflow, including OAuth checkpoints.

Token resolution order

TransportPriority
SSE / Streamable HTTPAuthorization: Bearer (OAuth access token or workspace token) → ?workspace_token= or ?token= query param → x-workspace-token / x-chatbo-token header → CHATBOTX_API_KEY env
stdioCHATBOTX_API_KEY env

Configuration

Copy .env.example to .env and fill in the values:

bash
cp .env.example .env
VariableDescriptionDefaultRequired
CHATBOTX_API_KEYWorkspace token for stdio only; leave empty on shared HTTP deployments—Yes (stdio)
CHATBOTX_API_URLChatbotX API origin, including /api (e.g. https://app.chatbotx.io/api)https://app.chatbotx.io/apiYes
CHATBOTX_ALLOW_SELF_SIGNED_CERTDisable TLS verification (true/false)—No
CHATBOTX_SPEC_TTL_MSHow long the fetched OpenAPI spec/tool list and a token's introspected scopes are trusted before a background re-fetch300000No
CHATBOTX_HTTP_TIMEOUT_MSMaximum duration for each OpenAPI, token introspection, or tool-call HTTP request30000No
CHATBOTX_MCP_TRANSPORTstdio | sse | bothbothNo
CHATBOTX_MCP_HOSTSSE server host0.0.0.0No
CHATBOTX_MCP_PORTSSE server port3333No
CHATBOTX_MCP_SSE_PATHSSE endpoint path/sseNo
CHATBOTX_MCP_MESSAGES_PATHJSON-RPC messages path/messagesNo
CHATBOTX_MCP_CORS_ORIGINCORS origin allowed to call the SSE/HTTP endpoints*No
CHATBOTX_MCP_SERVER_NAMEDisplay name sent to AI clientspackage nameNo
CHATBOTX_MCP_SERVER_INSTRUCTIONSInstructions sent to AI clients on connect (helps ChatGPT know when to call tools)built-in defaultNo
CHATBOTX_MCP_OAUTH_ENABLEDEnable OAuth 2.1 protected-resource metadata and bearer challengestrueNo
CHATBOTX_MCP_OAUTH_ISSUERAuthorization server issuer URLderived from CHATBOTX_API_URLNo
CHATBOTX_MCP_PUBLIC_URLCanonical public origin; required in production so metadata advertises the TLS endpointderived from request headersYes (production)

Scripts

bash
# Development with watch modepnpm dev:mcp
# Build for productionpnpm build
# Run built serverpnpm start
# Type checkpnpm check-types
# List loaded tools (requires CHATBOTX_API_URL and CHATBOTX_API_KEY in .env)dotenv -e .env -- tsx src/test-tools.ts

Evaluating tool selection

Two layers of evaluation cover search_tools/call_tool accuracy — a fast offline gate and a full LLM-driven business eval.

eval:search — offline ranking gate (no API key, seconds)

Scores every prompt in the eval corpus (evals/cases.ts) through the real searchTools() ranker against a real generated spec, with no LLM in the loop. Use this after any change to src/server/search/ or to a public route's summary/description.

  1. Dump the current OpenAPI spec (the builder test already has a hook for this — see apps/builder/__tests__/public-spec-operations.test.ts):
    bash
    MCP_EVAL_SPEC_OUTPUT=/absolute/path/public-spec.json \  pnpm --filter builder test -- public-spec-operations.test.ts
  2. Run the gate against it:
    bash
    pnpm --filter chatbotx-mcp eval:search --spec /absolute/path/public-spec.json [--min-top1 0.65] [--min-top3 0.85] [--verbose]
    Prints per-locale top-1/top-3/empty-result rates, but enforces the configured thresholds only for English. --verbose also lists every prompt that missed the top 3, with the ranker's actual top matches, for targeted ranking or description fixes.

eval:business — full LLM-driven business eval

Spins up a synthetic HTTP sandbox implementing the generated spec's operations, connects a real MCP client, and drives gpt-4o-mini/gpt-4.1-mini (or any @ai-sdk/openai-supported model) through the selected corpus. business contains 240 prompts (48 families × 5 locales: vi, vi-unaccented, colloquial, en, mixed); multilingual is the 80-case smoke matrix (16 families × en, vi-natural, es, fr, zh). Requires OPENAI_API_KEY.

bash
pnpm --filter chatbotx-mcp eval:business \  --spec /absolute/path/public-spec.json \  --out /absolute/path/out/baseline \  --phase smoke \  --seed 20260923 \  --models gpt-4o-mini,gpt-4.1-mini \  [--repeat N] \  [--corpus business|multilingual] \  [--exposure default|meta-only|both] \  [--cases family-a,family-b] \  [--server-source /absolute/path/to/apps/mcp-server]
  • --repeat N runs every selected case under every model and exposure N times. Smoke runs default to 3; baseline and candidate runs default to 1.
  • --exposure meta-only restricts the model's tool set to search_tools/call_tool only (no directly-listed default tools) — the path a client using only the default connection payload takes for any request outside the ~45 default-visible tools. both (the default) runs every case under both exposures.
  • Each episode is graded on semantic arguments, ordered tool sequences, its expected final HTTP state, API-error claims, post-failure mutations, and step exhaustion. The summary reports the pass rate per model × exposure × locale × family; episodes also record searchRank, callToolErrorCount, and unknownToolCount.
  • The smoke sandbox includes contact, conversation reply, flow, broadcast, appointment, and analytics fixtures. No public appointment-availability operation exists, so unavailable-slot coverage exercises appointments_book returning 422.
  • Compare two runs (regressions fail the command):
    bash
    pnpm --filter chatbotx-mcp eval:business --compare /absolute/path/out/baseline /absolute/path/out/candidate
    Reports any case that regressed from pass to non-pass, plus the average searchRank and total callToolErrorCount delta between the two runs.

Evaluation output is written under evals/out/ (gitignored) unless --out points elsewhere.

Project structure

src/├── index.ts                # Entry point — loads spec, starts transport(s)├── env.ts                  # Environment variable schema├── guides/                 # Packaged markdown operational guides├── http.ts                 # Timed fetch helper for OpenAPI, token, and tool requests├── openapi-loader.ts       # Fetches OpenAPI spec → DynamicTool list, x-mcp│                           # visibility/scope/HITL parsing, scope-filtered getVisibleTools()├── token-introspection.ts  # GET /v1/token → cached {permission, scopes} per token├── test-tools.ts           # Dev utility — prints loaded tools└── server/    ├── create-mcp-server.ts   # MCP server factory, resources, tools/list + tools/call    ├── hitl-gate.ts           # Two-step confirmation gate for mutations    ├── meta-tools.ts          # search_tools / call_tool / get_guide definitions    ├── execute-tool.ts        # Shared HTTP dispatch, confirmation, argument normalization    ├── search/                # search_tools ranking: normalization and IDF scoring    ├── sse-server.ts          # SSE / Streamable HTTP transport    └── stdio-server.ts        # stdio transport
evals/├── cases.ts           # Eval corpus: business-intent prompts × 5 locale variants├── sandbox.ts         # Synthetic HTTP server implementing the generated spec├── run.ts             # eval:business — drives an LLM through the MCP server└── search-audit.ts    # eval:search — offline ranking gate, no LLM

Troubleshooting

Tools not showing up

  • Check that CHATBOTX_API_URL is reachable and {CHATBOTX_API_URL}/public-spec.json returns a valid OpenAPI spec.
  • Only operations the spec marks x-mcp.visibility: "default" appear in tools/list — everything else is reachable via search_tools/call_tool. See "Default tools vs. the full API" above.
  • The spec/tool list refreshes automatically every CHATBOTX_SPEC_TTL_MS (default 5 minutes); a brand-new operation may take that long to appear without a restart.
  • A token missing a required scope, or a read_only token calling a write endpoint's tool, will not see that tool — see "Scope-based filtering" above.
  • Check stderr output on startup — the server logs Loaded N tools from OpenAPI spec.

Port already in use

bash
lsof -ti:3333 | xargs kill -9

Self-signed certificate errors

bash
CHATBOTX_ALLOW_SELF_SIGNED_CERT=true

SSE connection fails in Claude

  • Prefer stdio mode for local use — it has no network dependency.
  • For SSE, verify the server is running and the URL/port are reachable from the client.

ChatGPT uses its training knowledge instead of calling tools

  • Set CHATBOTX_MCP_SERVER_INSTRUCTIONS to explicitly instruct ChatGPT to use tools (see .env.example).
  • Make sure the connector URL includes ?workspace_token=<your-token> so authentication is handled automatically.

Source: apps/mcp-server/README.md at commit 14c9034

Tools

0
This server asks you to sign in, so SourceWeft could not read its tools without an account and has not indexed them. What a connected account sees can depend on that account and its permissions.

Version history

1
  1. v1.8.1LatestNov 6, 2026

Score

75% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts

    Declare a license in the repository or the registry entry.