Chatwoot MCP Server
# Chatwoot MCP Server
[](LICENSE)
[](https://nodejs.org)
[](https://www.typescriptlang.org)
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that connects AI assistants like Claude to your [Chatwoot](https://www.chatwoot.com) instance. Manage customer conversations, read messages, send replies, and filter by date ranges -- all through natural language.
## Features
- **5 MCP Tools** - List, filter, and inspect conversations; read and send messages
- **Advanced Filtering** - Filter conversations by date range, status, assignee, inbox, and labels
- **Dual Authentication** - API token (recommended) or JWT email/password
- **Type-Safe** - Built with TypeScript and OpenAPI-generated types
- **Dual Output** - Markdown (human-readable) and JSON (machine-readable) response formats
## Tools
| Tool | Description |
|------|-------------|
| `chatwoot_list_conversations` | List conversations with status, assignee, and inbox filters |
| `chatwoot_get_conversation` | Get full details for a specific conversation |
| `chatwoot_list_messages` | List all messages in a conversation |
| `chatwoot_create_message` | Send a reply or create an internal note |
| `chatwoot_filter_conversations` | Filter by date range, status, assignee, inbox, and labels |
## Quick Start
### Prerequisites
- [Node.js](https://nodejs.org) >= 18
- A Chatwoot account with API access
### Install
```bash
git clone https://github.com/mohnori/chatwoot-mcp.git
cd chatwoot-mcp
npm install
npm run build
```
### Configure
Copy the example environment file and fill in your credentials:
```bash
cp .env.example .env
```
Edit `.env`:
```bash
CHATWOOT_BASE_URL="https://your-chatwoot-instance.com"
CHATWOOT_API_TOKEN="your_api_token_here"
CHATWOOT_ACCOUNT_ID="your_account_id_here"
```
**Getting your API token:**
1. Log in to Chatwoot
2. Click your avatar → **Profile Settings**
3. Scroll to the bottom → copy your **Access Token**
**Getting your account ID:**
Your account ID is the number in the URL when you're logged in: `app.chatwoot.com/app/accounts/<ID>/...`
### Run
```bash
npm start
```
## MCP Configuration
### Claude Code
```bash
claude mcp add chatwoot \
-e CHATWOOT_BASE_URL="https://your-chatwoot-instance.com" \
-e CHATWOOT_API_TOKEN="your_api_token" \
-e CHATWOOT_ACCOUNT_ID="your_account_id" \
-- node /path/to/chatwoot-mcp/dist/index.js
```
> Replace `/path/to/chatwoot-mcp` with the actual path where you cloned the repository.
### Claude Desktop
Add to your Claude Desktop configuration file:
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"chatwoot": {
"command": "node",
"args": ["/path/to/chatwoot-mcp/dist/index.js"],
"env": {
"CHATWOOT_BASE_URL": "https://your-chatwoot-instance.com",
"CHATWOOT_API_TOKEN": "your_api_token_here",
"CHATWOOT_ACCOUNT_ID": "your_account_id_here"
}
}
}
}
```
> Replace `/path/to/chatwoot-mcp` with the actual path where you cloned the repository.
> On Windows, use double backslashes: `"C:\\Users\\you\\chatwoot-mcp\\dist\\index.js"`
### Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `CHATWOOT_BASE_URL` | Yes | Your Chatwoot instance URL (no trailing slash) |
| `CHATWOOT_ACCOUNT_ID` | Yes | Your Chatwoot account ID (numeric) |
| `CHATWOOT_API_TOKEN` | Yes* | API access token (recommended method) |
| `CHATWOOT_EMAIL` | Yes* | Email for JWT auth (alternative method) |
| `CHATWOOT_PASSWORD` | No | Password for JWT auth (needed for token refresh) |
*Either `CHATWOOT_API_TOKEN` or `CHATWOOT_EMAIL` is required.
## Tools Reference
### chatwoot_list_conversations
List conversations from an account with optional filters.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `status` | string | No | `"open"` | `"open"`, `"resolved"`, `"pending"`, `"snoozed"`, or `"all"` |
| `assignee_type` | string | No | - | `"me"`, `"unassigned"`, or `"all"` |
| `inbox_id` | number | No | - | Filter by inbox ID |
| `page` | number | No | `1` | Page number |
| `response_format` | string | No | `"markdown"` | `"markdown"` or `"json"` |
### chatwoot_get_conversation
Get detailed information about a specific conversation.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `conversation_id` | number | Yes | Conversation ID |
| `response_format` | string | No | `"markdown"` or `"json"` |
### chatwoot_list_messages
List all messages in a conversation.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `conversation_id` | number | Yes | Conversation ID |
| `response_format` | string | No | `"markdown"` or `"json"` |
### chatwoot_create_message
Send a message or create an internal note in a conversation.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `conversation_id` | number | Yes | - | Conversation ID |
| `content` | string | Yes | - | Message content |
| `message_type` | string | No | `"outgoing"` | `"outgoing"` or `"incoming"` |
| `private` | boolean | No | `false` | `true` for internal notes |
### chatwoot_filter_conversations
Filter conversations using advanced criteria. Uses Chatwoot's POST filter API with support for date ranges, status, assignee, inbox, and labels. Returns 25 results per page.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `date_from` | string | No | Created after this date (YYYY-MM-DD) |
| `date_to` | string | No | Created before this date (YYYY-MM-DD) |
| `activity_from` | string | No | Last activity after this date (YYYY-MM-DD) |
| `activity_to` | string | No | Last activity before this date (YYYY-MM-DD) |
| `status` | string | No | `"open"`, `"resolved"`, `"pending"`, or `"snoozed"` |
| `assignee_id` | number | No | Filter by assignee agent ID |
| `inbox_id` | number | No | Filter by inbox ID |
| `label` | string | No | Filter by label name |
| `page` | number | No | Page number (default: 1) |
| `response_format` | string | No | `"markdown"` or `"json"` |
**Date filter behavior:** Date boundaries are exclusive. To get conversations for a single day like Feb 21, use `date_from="2026-02-20"` and `date_to="2026-02-22"`.
## Example Queries
Once connected, you can ask Claude things like:
- "Show me all open conversations"
- "What are the details of conversation #123?"
- "List all messages in conversation #456"
- "Send a reply to conversation #789 saying 'Thank you for contacting us!'"
- "Add an internal note to conversation #101 about the customer's issue"
- "Find all conversations created on Feb 21"
- "Show me resolved conversations from last week with the label 'urgent'"
## Development
### Project Structure
```
chatwoot-mcp/
├── src/
│ ├── index.ts # MCP server entry point & tool registration
│ ├── constants.ts # Shared constants and enums
│ ├── chatwoot-types.ts # Auto-generated OpenAPI types
│ ├── services/
│ │ ├── chatwoot-client.ts # API client with auth middleware
│ │ ├── chatwoot-auth.ts # JWT authentication
│ │ ├── token-cache.ts # JWT token persistence
│ │ └── error-handler.ts # Error formatting utilities
│ ├── schemas/
│ │ └── common.ts # Shared Zod validation schemas
│ └── tools/
│ ├── conversations.ts # List & get conversation tools
│ ├── messages.ts # List & create message tools
│ └── filter-conversations.ts # Advanced conversation filtering
├── test/
│ ├── chatwoot-client.test.ts # Integration tests
│ ├── setup.ts # Test environment setup
│ └── unit/ # Unit tests (mocked, no API calls)
│ ├── error-handler.test.ts
│ ├── build-filter-payload.test.ts
│ ├── conversations.test.ts
│ ├── messages.test.ts
│ ├── filter-conversations.test.ts
│ ├── schemas.test.ts
│ ├── chatwoot-auth.test.ts
│ └── token-cache.test.ts
├── .env.example # Environment variable template
├── package.json
├── tsconfig.json
└── vitest.config.ts
```
### Scripts
| Command | Description |
|---------|-------------|
| `npm run build` | Compile TypeScript to `dist/` |
| `npm start` | Run the compiled server |
| `npm run dev` | Run in development mode with auto-reload |
| `npm test` | Run integration tests |
| `npm run test:watch` | Run tests in watch mode |
| `npm run clean` | Remove the `dist/` directory |
| `npm run generate-types` | Regenerate OpenAPI types from swagger.json |
### Regenerating Types
If the Chatwoot API changes, download the latest OpenAPI spec and regenerate types:
1. Download `swagger.json` from your Chatwoot instance at `/swagger/v1/swagger.json`
2. Place it in the project root
3. Run `npm run generate-types`
### Running Tests
Unit tests run without any credentials. Integration tests require a real Chatwoot instance:
```bash
# Unit tests only (no credentials needed)
npm test -- test/unit/
# All tests (requires .env with valid credentials)
cp .env.example .env
# Edit .env with your credentials
npm test
```
## Troubleshooting
### API Token Returns 401
If using a self-hosted Chatwoot with nginx, add this to your nginx config:
```nginx
server {
underscores_in_headers on; # Required for api_access_token header
}
```
### JWT Tokens Expire
JWT tokens expire (typically after 2 weeks). Keep `CHATWOOT_PASSWORD` in your `.env` for automatic refresh, or switch to API token authentication.
### MCP Connection Errors
If you see JSON parsing errors when connecting, ensure you are using `node dist/index.js` directly (not `npx`). Some npm packages output debug information to stdout during installation, which corrupts the MCP stdio protocol.
## Tech Stack
- **[@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)** - MCP server framework
- **[openapi-fetch](https://github.com/openapi-ts/openapi-typescript)** - Type-safe API client
- **[openapi-typescript](https://github.com/openapi-ts/openapi-typescript)** - OpenAPI type generation
- **[Zod](https://github.com/colinhacks/zod)** - Runtime schema validation
- **[Vitest](https://vitest.dev)** - Test framework
## Attribution
Originally created by [Hugo Blanc](https://github.com/hugoblanc/chatwoot-mcp).
## License
[MIT](LICENSE)
## Contributing
Contributions are welcome! Some ideas for additional tools:
- Contact management (create, update, search)
- Team and agent operations
- Inbox configuration
- Labels and custom attributes
- Reports and analytics
TDQS
Scored across 5 tools
list_conversations and filter_conversations overlap significantly; both retrieve conversations with filtering, though filter adds date/label/advanced criteria. The other three tools (get_conversation, list_messages, create_message) are clearly distinct.
All tools follow a consistent chatwoot_ verb_noun pattern in snake_case: list_conversations, get_conversation, list_messages, create_message, filter_conversations. No style mixing or irregularities.
Five tools is a reasonable size for a focused Chatwoot conversation/message server. It feels slightly thin compared to the full platform scope, but each tool has a distinct role and the count is appropriate for a targeted integration.
Core read and send workflows are covered (list/get conversations, list/create messages), but there are notable gaps: no way to update conversation status, assignee, or labels, and no create conversation or contact management. The surface handles common support tasks but lacks lifecycle management.