Chat Thing
Chat Thing MCP Server The official Chat Thing MCP server.
Community: Submitted by a user or imported; check the owner before granting accessOnlineNo sign-inGlobalFreeCan modify data
What it can do
- List Teams: List teams the authenticated user is a member of, with their role on each team. Use this to discover the teamId required by `create_bot` when the user belongs to multiple teams. The `role`
- List Models: List the LLM models available for use as a bot's primary model. Use the `type` field as the `model` argument to `create_bot` or `update_bot` (e.g. `claude46Sonnet`, `gpt5`). The MCP tools
- List Bots: List bots belonging to teams the authenticated user is a member of. Optionally filter by teamId. Each bot's `version` is included so you can tell v2 bots (editable via `update_bot`) from le
What data it sees
Do you need an account
No: the server works without sign-in
Chat Thing MCP Server
The official Chat Thing MCP server. Build, configure, brand, and test AI agents end to end, directly from Claude or any MCP client.
What you can do
- Create and manage agents — spin up new agents and update their config, model, and behaviour
- Connect data sources — add and sync websites, RSS feeds, YouTube, or manual content so your agent answers from real knowledge
- Add power-ups — wire in human hand-off, email, and API webhooks for escalation and actions
- Set up channels — configure web channels and hooks to deploy your agent where your users are
- Test before you ship — run test cases and chat with your agent to check answers and sources
Who it's for
For teams who want AI-native support agents, not clunky decision-tree bots. Grounded in your knowledge, built to deflect tickets, and ready to hand off to a human when needed.
Server tool list (47)
Raw names from tools/list. Only developers need these.
| list_teams | List teams the authenticated user is a member of, with their role on each team. Use this to discover the teamId required by `create_bot` when the user belongs to multiple teams. The `role` field indicates write access — only `owner` and `admin` can mutate bots, data sources, etc. via MCP. |
| list_models | List the LLM models available for use as a bot's primary model. Use the `type` field as the `model` argument to `create_bot` or `update_bot` (e.g. `claude46Sonnet`, `gpt5`). The MCP tools accept the friendly `type` enum so the caller never has to handle the underlying UUID. Deprecated models are excluded. |
| list_bots | List bots belonging to teams the authenticated user is a member of. Optionally filter by teamId. Each bot's `version` is included so you can tell v2 bots (editable via `update_bot`) from legacy v1 bots (not editable via MCP). |
| get_bot | Get a single bot's configuration, including every field `update_bot` can write (name, description, systemMessage, firstMessage, exampleQuestions, responseGuard, includeSources, allowFeedback, allowChatSummary, temperature, documentRelevance, documentChunkSize, enhancedRetrieval, multiModal, maxContextAmount, maxMessageCharLimit, maxMessageCharLimitValue, modelId) plus `version`. Read these before editing so you can change one value and write the rest back unchanged. `update_bot` only edits v2 bots - check `version` first. |
| list_chats | List recent conversations for a bot with basic metadata (createdAt, message count). |
| get_messages | Get the messages in a chat (role, content, createdAt), each with its `sources` (the data source rows the answer drew from, when the bot has includeSources enabled) and `display` (the rich display payload a display power-up rendered — cards, charts, tables — null otherwise). Only returns messages for chats belonging to the user's teams. By default, hidden messages (system messages, tool-call scaffolding, etc.) are excluded — set `includeHidden: true` if you specifically want them. |
| list_data_sources | List data sources attached to a bot (with current sync state). |
| get_data_source | Get a single data source with current sync state and config. Primary tool for polling after add_data_source/sync_data_source. |
| list_data_source_rows | Paginated list of the rows inside a single data source, with stable row ids. Type-generic (WEB/RSS/YOUTUBE/MANUAL/NOTION/etc.). Use this to enumerate the URLs (or manual entries / feed items) in a source — `get_data_source` returns config + sync state but no rows — and to obtain the `id` values that `update_data_source(removeRowIds)` accepts. Access is scoped to the caller's teams. |
| list_discovered_pages | Paginated full URL list + state for a discovery created by `discover_pages`. Use this for `crawl` discoveries (polling for state=ready) or when you need to enumerate URLs beyond what the discover_pages summary returned. Discoveries expire after one hour; access is scoped to the caller's teams. |
| update_bot | Update a v2 bot's configuration. Writable fields: name, description, systemMessage, firstMessage, exampleQuestions, responseGuard, includeSources, allowFeedback, allowChatSummary, temperature, documentRelevance, documentChunkSize, enhancedRetrieval, multiModal, maxContextAmount, maxMessageCharLimit, maxMessageCharLimitValue, and the model - any other field returns an error. The model can be set via the friendly `model` enum (preferred - call `list_models` to discover valid values) or via raw `modelId`. Only v2 bots can be edited via MCP; editing a legacy v1 bot returns an error asking you to migrate it to v2 in the dashboard first (call `get_bot` to check a bot's `version`). Caller must be an owner or admin on the bot's team. Provide an optional `rationale` to help us understand how MCP is being used. |
| create_bot | Create a new bot with a name, system message, and optional initial model. The new bot has a default web channel attached so it's immediately testable. Next steps after this call: (1) call `add_data_source` for any URLs/text the bot should know about; (2) poll `get_data_source` until each source reaches state `synced` or `sync_error`; (3) open the returned `dashboardUrl` to test the bot or wire up additional channels (Slack, Discord, embed, etc.). If the user is owner/admin on exactly one team, `teamId` can be omitted. Otherwise call `list_teams` first to discover the right teamId. Caller must be an owner or admin on the chosen team. |
| start_chat | Open a new chat against a bot so it can be tested via `send_message`. Returns a `chatId`. Any member of the bot's team can start a chat (read access). Pair with `send_message` to ask the bot questions and read its replies - the usual flow after building a bot from scratch. Optional `userData` attaches identity/context to the conversation. |
| send_message | Send a user message to a chat (created via `start_chat`) and get the bot's full reply back in a single response. Use this to verify a bot answers correctly from its knowledge after building it. Any member of the bot's team can call this (read access); note it spends the team's tokens. Besides the reply text, the response carries `sources` — the data source rows the answer drew from (when the bot has includeSources enabled), each with its type and config (e.g. the page URL for WEB sources) — and `displays`, the rich display payloads (cards, charts, tables, maps, diagrams) any display power-up rendered during the reply, exactly as the widget would receive them. Both are empty arrays when nothing applies, so QA flows can assert on which pages an answer cited and what a display power-up actually rendered. |
| delete_bot | DESTRUCTIVE AND IRREVERSIBLE — there is no undo. Deletes a bot and queues a background job that permanently purges its chats, messages, data sources, documents/embeddings, channels, and uploaded files; none of it can be recovered. Only the bot row is flagged deleted synchronously (it stops responding immediately), but the cascade purge runs asynchronously, so the bot may briefly still appear in list_bots before its data is gone. Only call this for bots you are certain should be destroyed, e.g. throwaway test bots. Caller must be an owner or admin on the bot's team. |
| add_data_source | Add a new data source to a bot's knowledge base. The required `type` (one of WEB, RSS, YOUTUBE, MANUAL) decides the payload: URL-based types take a `urls` array; MANUAL takes a `rows` array of `{ title?, text }`, each entry becoming one page/row, mirroring how `urls` seeds one row per URL. `urls` seeds one or more pages/feeds/videos into a single data source in one call — each URL becomes one page; pass a single-element array for one URL. Every URL is validated against the type's expected pattern (YouTube hosts for YOUTUBE, feed-shaped paths for RSS, etc.) and against the network safety policy (private/loopback/reserved ranges rejected); if any URL fails validation the whole call is rejected. For WEB sources you may instead commit a prior `discover_pages` result by passing `discoveryId` (provide `urls` OR `discoveryId`, never both, never neither). Use `includePatterns`/`excludePatterns` (URL-path globs — which pages) to narrow the discovery before committing; matched pages become discovered rows. This tool is asynchronous: it returns immediately with state 'syncing' and the source goes through scrape → embed in the background. Poll `get_data_source` every 5–10s to observe sync progress. Terminal states are `synced` (success — the bot can now answer from this source) and `sync_error` (failure — check `stateMeta` for details). Larger pages and YouTube videos can take 30–60s; more URLs take proportionally longer. The number of URLs added is clamped to the team's per-bot page limit; the response reports `pageCount` and whether the list was `truncated`. RSS feeds additionally discover their own items during sync. WEB/RSS sources accept optional `contentSelector` (a single CSS selector for the part of each page to extract) and `contentExcludes` (CSS selectors to strip) — set them at the source level to apply to every URL, or per URL via `{ url, contentSelector?, contentExcludes? }` to override. These pick page content, distinct from `includePatterns`/`excludePatterns` which pick which pages. When omitted the scraper defaults to `selector: 'body'` and `excludes: ['header','footer']`. Both are ignored for YOUTUBE/MANUAL. Caller must be an owner or admin on the bot's team. |
| update_data_source | Update an EXISTING data source — grow, prune, and reconfigure it without rebuilding (the additive 'update' half of `add_data_source`). Type-generic (WEB/RSS/YOUTUBE/MANUAL). Append: `addUrls` (WEB/RSS/YOUTUBE) appends one row per URL; `addDiscoveryId` (WEB only) commits a prior `discover_pages` result, filtered by `includePatterns`/`excludePatterns`; `addRows` (MANUAL only) appends manual entries. Appends are bounded by the team's per-bot page limit against the existing row count — a large discovery can't flood a source in one call (the response reports clamping). Remove: `removeRowIds` deletes specific rows. Removal is durable — and therefore allowed — when a row is seeded (discovered=false, any type) OR the source is WEB (web never re-crawls). Removing a discovered row of a re-discovering type (RSS/YOUTUBE/NOTION/GOOGLE) is REJECTED: the next re-sync re-creates it from the feed/playlist, so remove it at the source instead. Discovered RSS/YouTube items are managed by the feed, not here. If any requested id is invalid the whole call is rejected and nothing is deleted. Reconfigure: `label`, `syncInterval`, `contentSelector`/`contentExcludes` (WEB/RSS scrape config), and WEB basic-auth `username`/`password`. After mutating, the source re-syncs in the background (fire-and-forget); poll `get_data_source` until state is `synced` or `sync_error`. Caller must be an owner or admin on the bot's team. |
| sync_data_source | Trigger a re-sync on an existing data source — useful after the underlying URL has been updated, or to retry after `sync_error`. Returns state 'syncing'; poll `get_data_source` until state is `synced` or `sync_error`. Caller must be an owner or admin on the bot's team. |
| discover_pages | Discover the URLs of a site without ingesting them — first step of the two-step crawl flow. Returns a `discoveryId` plus a summary of what was found (path-tree grouped counts + a sample); the agent then refines include/exclude patterns and calls `add_data_source` with `type: "WEB"` and this `discoveryId` (plus optional `includePatterns`/`excludePatterns`) to commit. Use `list_discovered_pages` if you need the paginated full URL list. Summary fields: `samplePages` is a SAMPLE when `sampleTruncated` is true — the full stored list is always available via `list_discovered_pages`; no pages were dropped from the discovery itself. `cappedFromTotal`, when present, is the site's pre-cap URL count — its presence means the page cap (plan limit or `maxPages`) dropped URLs beyond `matchedCount`. Discoveries expire after one hour. The full URL list is held server-side keyed by `discoveryId` — the agent never has to round-trip an N-page array. |
| delete_data_source | DESTRUCTIVE AND IRREVERSIBLE — there is no undo. Deletes a data source and queues a background job that permanently purges its rows and embedded documents; the content cannot be recovered (you would have to re-add and re-sync the source to restore it). The data source row is flagged deleted synchronously, but the cascade purge runs asynchronously. Caller must be an owner or admin on the bot's team. |
| list_power_up_types | List the power-up types that can be created via MCP. Each entry carries the `type` identifier, a human title and description, a category (display | search | integration | communication | utility), `requiresProvider` — the OAuth provider (notion, google, nylas) the bot's team must have connected before instances of that type can be created (null when none is needed; check with `list_provider_connections`) — and `supportsDisplay`, whether instances of the type can render rich display output (cards, charts, tables) in chat. Call `get_power_up_schema` with a `type` from this list to get the exact JSON Schema for its config before calling `create_power_up`. |
| get_power_up_schema | Get the full JSON Schema for a power-up type's body (type, name, description, config). Use this before `create_power_up` or `update_power_up` so the `config` you send validates first time. Only types listed by `list_power_up_types` are accepted. |
| list_power_ups | List the power-ups attached to a bot, with each instance's id, type, name, description, enabled state, and config. Secret values in config are masked with a fixed placeholder — echoing the placeholder back via `update_power_up` keeps the stored value. Instances of types not offered by `list_power_up_types` are still listed (they can be updated/deleted, just not created, via MCP). Also the dedupe source of truth: retried creates are not deduplicated, so check here before re-creating. |
| list_provider_connections | Read a team's OAuth provider connection state (notion, google, nylas) — the prerequisite check for power-up types whose `requiresProvider` is set. Connecting a provider cannot be done via MCP: a human must open the returned `connectUrl` (the Connected services page) in their browser, verify the dashboard is operating in the intended team, and connect the service there. |
| create_power_up | Create a power-up on a bot. Call `get_power_up_schema` first and validate your `config` against it — rejected configs return field errors plus the full JSON Schema so you can self-correct. Types whose `requiresProvider` is set need the bot's team to have that provider connected; when it isn't, this returns a structured `provider_not_connected` result with a connect link for the user instead of creating anything. Retried creates are NOT deduplicated — call `list_power_ups` first if an earlier attempt may have succeeded. Caller must be an owner or admin on the bot's team. |
| update_power_up | Update a power-up's name, description, and/or config. `config` is replaced WHOLESALE, not merged: omitted non-secret config fields reset to their schema defaults — read the current config via `list_power_ups` first and write the full config back with your changes. Declared secret fields are the exception: echoing the masked placeholder or omitting them keeps the stored secret; sending a new value rotates it. A power-up's `type` is immutable — to change type, delete this power-up and create a new one. Caller must be an owner or admin on the bot's team. |
| delete_power_up | DESTRUCTIVE AND IRREVERSIBLE — there is no undo. Permanently deletes a power-up and its configuration (including any stored secrets, which cannot be recovered; you would have to re-create the power-up and re-supply them). The type's onDelete cleanup runs first — if it fails, nothing is deleted. If you only want to stop the bot using a power-up temporarily, use `toggle_power_up_enabled` instead. Caller must be an owner or admin on the bot's team. |
| toggle_power_up_enabled | Enable or disable a power-up without changing its configuration — the reversible alternative to delete_power_up. Disabled power-ups keep their config (including secrets) but are not offered to the bot's model. Caller must be an owner or admin on the bot's team. |
| get_web_channel_schema | Get the full JSON Schema for a bot's web channel (chat widget) config — locale, password protection, widget theming colours, branding toggles, SDK flags, and the pre-chat form. Use this before `update_web_channel` so the `config` you send validates first time. |
| get_web_channel | Read a bot's web channel (chat widget): its enabled state and config (theming, pre-chat form, behaviour flags). The password is write-only — reads show the masked placeholder and `passwordSet` tells you whether one is stored. A bot without a web channel gets one auto-created with an empty config. |
| update_web_channel | Update a bot's web channel (chat widget): enable/disable it and/or update its config — theming colours, branding toggles, pre-chat form, behaviour flags. `config` is MERGED over the stored config at the top level: send only the fields you want to change and omitted fields keep their stored values (arrays like preChatFormFields are replaced whole when provided). Sending any theming field (themeMode, colours, icons) turns `themingEnabled` on unless the call sets it explicitly. The `password` field is write-only: send a new plaintext value to set it (stored hashed), echo the masked placeholder or omit it to keep the stored one. Setting `passwordEnabled: true` requires a password to be stored or supplied. The channel's type is always `web` — it cannot be changed. Caller must be an owner or admin on the bot's team. |
| list_hook_types | List the webhook (hook) types a bot supports. Each entry carries the `type` identifier, a one-line description, `direction` (`outgoing` hooks deliver signed payloads to your `target` URL; the `incoming` StartSync hook is triggered by calling its public URL), `testable` (whether `test_hook` can fire a sample delivery), and `requiresDataSourceId` (true = a data source id is required, "optional" = may scope to one data source, false = not applicable). Call `get_hook_schema` with a type from this list before `create_hook`. |
| get_hook_schema | Get the full JSON Schema for one hook type's body (botId, dataSourceId, config, enabled). Use mode `create` (default) before `create_hook` and mode `update` before `update_hook` — update mode requires fields (like a non-empty `target` and a stored `secret`) that create mode defaults. Note: update-mode schemas describe the full stored row, so they include row-level fields (`id`, `botId`, `enabled`) that `update_hook` does NOT accept — `enabled` is managed via `toggle_hook_enabled`, and `update_hook` accepts only `hookId`, `config`, `dataSourceId`, and `rationale`. |
| list_hooks | List the webhooks (hooks) configured on a bot, with each hook's id, type, enabled state, dataSourceId, and config. Secret values in config are masked with a fixed placeholder — echoing the placeholder back via `update_hook` keeps the stored value; the plaintext secret is only ever shown once, in the `create_hook` response. Also the dedupe source of truth: retried creates are not deduplicated, so check here before re-creating. |
| create_hook | Create a webhook on a bot. Hooks are ALWAYS created disabled regardless of any enabled value you send (R23) — the intended flow is create_hook -> test_hook -> toggle_hook_enabled. The signing secret (supplied, min 32 chars, or auto-generated) is returned in PLAINTEXT exactly once in this response and masked on every read after — store it immediately. Call `get_hook_schema` first; rejected configs return field errors plus the full JSON Schema so you can self-correct. Outgoing `target` URLs must be external and publicly reachable (private/loopback addresses are rejected). Retried creates are NOT deduplicated — call `list_hooks` first if an earlier attempt may have succeeded. Caller must be an owner or admin on the bot's team. |
| update_hook | Update a hook's config and/or data source scoping. Accepts only `hookId`, `config`, `dataSourceId`, and `rationale` — row-level fields shown by update-mode `get_hook_schema` (`id`, `botId`, `enabled`) are not writable here; `enabled` is managed via `toggle_hook_enabled`. `config` is replaced WHOLESALE, not merged — read the current config via `list_hooks` first and write the full config back with your changes. Omitting `config` entirely keeps the stored config as-is (a dataSourceId-only update works even on draft hooks whose config is still incomplete). `secret` is write-only: echo the masked placeholder or omit it to keep the stored secret, or send a new 32+ char value to rotate it (lost-secret recovery: if you didn't capture the secret from `create_hook` — e.g. a retried create — rotate it here with a new value and delete any duplicate hook with `delete_hook`). A hook's `type` is immutable — to change type, delete this hook and create a new one. Outgoing `target` URLs are re-validated: they must be external and publicly reachable. Use `toggle_hook_enabled` to enable/disable. Caller must be an owner or admin on the bot's team. |
| toggle_hook_enabled | Enable or disable a hook without changing its configuration. Hooks are created disabled — the intended flow is create_hook -> test_hook -> toggle_hook_enabled. Disabled hooks keep their config (including the secret) but never fire (and an incoming StartSync hook's public URL stops triggering syncs). Caller must be an owner or admin on the bot's team. |
| delete_hook | DESTRUCTIVE AND IRREVERSIBLE — there is no undo. Permanently deletes a hook and its configuration, including the stored signing secret (which cannot be recovered; receivers verifying signatures with it must be reconfigured if you re-create the hook). If you only want to stop the hook firing temporarily, use `toggle_hook_enabled` instead. Caller must be an owner or admin on the bot's team. |
| test_hook | Fire a sample delivery at an outgoing hook's target URL using the stored config and a realistic sample payload for its event type. Works while the hook is disabled — the intended flow is create_hook -> test_hook -> toggle_hook_enabled. Returns the remote response (success, status, body) plus warnings about unresolved {{tokens}} or content-type mismatches in custom body templates. The incoming StartSync type is not testable this way — the result points at its public trigger URL instead. Caller must be an owner or admin on the bot's team. |
| upload_image | Upload an image for a bot and get back a permanent public URL — the missing step for branding a bot entirely via MCP. Provide the image either as a public `url` (fetched server-side; private/internal addresses are rejected) or as `base64` bytes with a `filename`. Supported formats: png, jpg, jpeg, gif, webp, svg, avif, ico; max 5MB. Use the returned URL as `assistantIcon` / `userIcon` in `update_web_channel` config to set the chat widget avatars. Caller must be an owner or admin on the bot's team. |
| list_test_cases | List a bot's test cases (evals) with their checks. A test case is a question plus one or more checks (factuality, similarity, requirements, relevance) asserted against the bot's answer. Enterprise plan only - non-Enterprise teams get an upgrade message. Caller must be a member of the bot's team. |
| create_test_case | Create a test case (eval) for a bot: a `question` plus a `checks` array. Each check has a `type` (factuality | similarity | requirements | relevance), an optional `statement` (the requirement/expected fact to assert), and an optional `threshold` (0-1 score gate for similarity/relevance). `factuality` checks ignore threshold. Enterprise plan only. Caller must be an owner or admin on the bot's team. |
| update_test_case | Update a test case's question and reconcile its checks. Send the full desired `checks` array: entries with an existing check `id` are updated, entries without an `id` are created, and stored checks absent from the array are deleted. A `check.id` that does not belong to this case is ignored. Enterprise plan only. Caller must be an owner or admin on the bot's team. |
| delete_test_case | Delete a test case and its checks. Irreversible. Past test-run snapshots that referenced this case keep their copied data. Enterprise plan only. Caller must be an owner or admin on the bot's team. |
| list_test_runs | List a bot's test runs (eval executions), newest first, with their state (waiting | running | failed | complete) and timing. Use get_test_run to read a run's per-case results. Enterprise plan only. Caller must be a member of the bot's team. |
| start_test_run | Create and start a test run for a bot: snapshots the bot's current settings and all its test cases, then enqueues the run. Returns the `testRunId` and `state`. Runs execute asynchronously on a background worker - poll get_test_run until `state` is `complete` or `failed` (give up after a reasonable wall-clock cutoff from the run's startedAt, since a dead worker can leave a run stuck in `running`). Fails if the bot has no test cases. Note: the run evaluates against the bot's LIVE config at execution time, not the snapshot. Enterprise plan only. Caller must be an owner or admin on the bot's team. |
| get_test_run | Read a test run with its per-case results: each case's question, the bot's response, response time and tokens, and each check's pass/score/reason. Poll this after start_test_run until `state` is `complete` or `failed`. Enterprise plan only. Caller must be a member of the bot's team. |