Skip to main content
Glama
README.md
[English](README.md) | [Русский](README.ru.md) · [![Support on DonationAlerts](https://img.shields.io/badge/Support-DonationAlerts-orange)](https://www.donationalerts.com/r/svwergio_mel)

# chat-export-server

<p align="center">
  <img src="docs/media/demo-server.gif" alt="Native start on :8765, health, two Chrome profiles online/offline" width="720" />
</p>

**Local MCP server** for the [Chat Export](https://github.com/svergio/chat-export-extension) Chrome extension. List, read, export, create, delete, and **ask** in your own chats on **eight** web providers (ChatGPT, Grok, X Grok, Claude, GitHub Copilot, Qwen, DeepSeek, Perplexity) — through the extension in **your** browser. Everything stays on `127.0.0.1`: job queues, SQLite chat cache, audit log, optional [dashboard](https://github.com/svergio/chat-export-dashboard) UI.

## Why this MCP (for awesome-list reviewers)

Most LLM MCP servers wrap a **vendor HTTP API** (keys, quotas, cloud data path). Chat Export is different: the agent talks MCP to a **local** process; that process drives the **web UIs you are already logged into** via the Chrome extension bridge. No OpenAI/Anthropic/xAI API keys for chat ops, no chat bodies leaving `127.0.0.1`, and delete/create stay off until you opt in (`allowDestructive` + `confirm`). Pair with the [extension zip](https://github.com/svergio/chat-export-extension/releases/tag/v2.0.3); point Cursor (or any MCP client) at `http://127.0.0.1:8765/mcp`.

## The problem

IDE agents need **structured access** to web LLM sessions without pasting cookies or paying per-token cloud APIs. You want MCP tools, retries, and queues — but data must not leave your machine.

## What you get

| Platform | Automation |
|----------|------------|
| ChatGPT | list / get / export / create / delete / ask |
| Grok (`grok.com`) | same |
| X Grok | same |
| Claude | same |
| GitHub Copilot web | same |
| Qwen (`chat.qwen.ai`) | same |
| DeepSeek (`chat.deepseek.com`) | same |
| Perplexity (`perplexity.ai`) | same |

```mermaid
flowchart TB
  EXT[Chrome extension] <-->|WS /ws ceb_| HUB[Browser hub]
  HUB --> Q[Job lanes per browser]
  Q --> MCP[MCP /mcp]
  MCP --> AGENT[Cursor etc. cem_/cek_]
  HUB --> API[Dashboard /dashboard/api]
  API --> UI[Dashboard static UI]
  Q --> DB[(SQLite cache + WAL)]
```

## Quick start (3 steps)

1. **Extension** — load [chat-export-extension](https://github.com/svergio/chat-export-extension) unpacked; enable bridge in popup; open provider tabs logged in.
2. **Server** — `npm install && npm run build`, `chat-export-server key new`, `chat-export-server start` → `http://127.0.0.1:8765`.
3. **MCP client** — point to `http://127.0.0.1:8765/mcp` with `Authorization: Bearer <key>`; run `browsers_bind` then `chats_list` / `chats_export` / `chat_ask`.

Wiki: [MCP tools and profiles](https://github.com/svergio/chat-export-extension/wiki).

## Install and build

```sh
npm install
npm run build   # tsc -> dist/
npm link        # optional: chat-export-server on PATH
```

Requires **Node 22.13+** (`node:sqlite`).

| Script | Purpose |
| --- | --- |
| `npm run build` | compile to `dist/` |
| `npm run typecheck` | `tsc --noEmit` |
| `npm start` | `node dist/cli/index.js start` |
| `npm run dev` | `tsx watch src/cli/index.ts start` |
| `npm run mcp` | stdio MCP attached |

### First run

```sh
chat-export-server key new    # print once; hash stored
chat-export-server start
# WS   /ws, /ext  — extension bridge
# MCP  /mcp       — Bearer key
# GET  /health
```

Data under `~/.chat-export` (override `CHAT_EXPORT_HOME`):

```text
~/.chat-export/
  config.json    # host, port, exportDir
  keys.json      # hashes only (chmod 600)
  audit.log      # MCP/RPC audit
  exports/       # chats_export output
```

```sh
chat-export-server key rotate
chat-export-server key list
chat-export-server status
```

## Configuration

### Environment variables

Copy [`.env.example`](.env.example) to `.env` in the server directory (or set `CHAT_EXPORT_ENV_FILE`). Container and process env override `config.json` where noted.

| Variable | Purpose |
|----------|---------|
| `CHAT_EXPORT_HOME` | Data directory (default `~/.chat-export`; `/data` in Docker) |
| `CHAT_EXPORT_HOST` | Bind address (`127.0.0.1` locally; use `0.0.0.0` in containers) |
| `CHAT_EXPORT_PORT` | HTTP port (default `8765`) |
| `CHAT_EXPORT_ALLOWED_HOSTS` | Extra `Host` header names allowed (comma-separated) |
| `CHAT_EXPORT_DASHBOARD_ENABLED` | `true` / `false` |
| `CHAT_EXPORT_ADMIN_USER` / `CHAT_EXPORT_ADMIN_PASS` | Dashboard login (overrides `config.json`) |
| `CHAT_EXPORT_MCP_TOKEN` | Optional preset `cem_…` token hash on start |
| `CHAT_EXPORT_BROWSER_TOKENS` | `browserId:ceb_…[:label]` comma list for auto-enroll |
| `CHAT_EXPORT_ALLOW_DESTRUCTIVE` | `true` / `false` |
| `CHAT_EXPORT_DB_DRIVER` | DB driver override (`sqlite` default) |
| `CHAT_EXPORT_DB_URL` | DB URL when not using default SQLite path |
| `CHAT_EXPORT_SKIP_MCP_CONFIG` | Set `1` to skip auto-writing Cursor MCP config on `key new` |

### Docker and Colima

This repo ships a **multi-stage** [`Dockerfile`](Dockerfile) (Node 22 Alpine, non-root user, `CHAT_EXPORT_HOME=/data`, listen `0.0.0.0:8765`, `/health` check). **Docker Desktop is not required** — use [Colima](https://github.com/abiosoft/colima) on macOS:

```sh
colima start
docker context use colima   # or: docker --context colima …
cp .env.example .env        # set CHAT_EXPORT_ADMIN_PASS at minimum
docker --context colima compose build
docker --context colima compose up -d
curl -sS http://127.0.0.1:8765/health
```

Published only on **`127.0.0.1:8765`**. Persistent data: Compose volume `chat-export-data` → `/data`.

Stop when finished so a local `chat-export-server` daemon can reclaim the port:

```sh
docker --context colima compose down
```

Optional **split stack** (nginx serves dashboard static, proxies `/dashboard/api`, `/mcp`, `/ws`, `/ext`, `/enroll`, `/health` to the server): build from the maintainer tree `chat-export-dashboard/Dockerfile` and `projects/Chat Export/docker-compose.yml` (see [dashboard repo](https://github.com/svergio/chat-export-dashboard)).

### `config.json` (under `CHAT_EXPORT_HOME`)

Created on first start. Example (secrets redacted):

```json
{
  "host": "127.0.0.1",
  "port": 8765,
  "exportDir": "~/.chat-export/exports",
  "rpcTimeoutMs": 60000,
  "dashboard": {
    "enabled": true,
    "username": "admin",
    "password": "changeme"
  },
  "registeredBrowsers": [],
  "settings": {
    "platformsEnabled": ["chatgpt", "grok", "grok-x", "copilot", "claude"],
    "allowDestructive": false
  }
}
```

Change **`dashboard.password`** before exposing the host beyond loopback. Server listens on **`127.0.0.1:8765`** by default (`/health`, `/mcp`, `/ws`, `/dashboard/`).

### Tokens

| Prefix | Used by |
|--------|---------|
| `cek_` / `cem_` | MCP and CLI (`Authorization: Bearer …` on `/mcp`) |
| `ceb_` | Chrome extension WebSocket (`/ws`); enroll via CLI or [dashboard](https://github.com/svergio/chat-export-dashboard) |

Only **hashes** of MCP keys are stored in `keys.json` (mode `600`). Plaintext is shown once at `chat-export-server key new`.

### Detached daemon (maintainer workspace)

In the Chat Export maintainer tree, `tmp-scripts/ensure-daemon.mjs` can keep `chat-export-server` running on `:8765`, write `~/.chat-export/server.pid`, and optionally sync `Bearer cem_…` into `.cursor/mcp.json` (`--sync-mcp-json`). Equivalent manual start: `chat-export-server start`.

### Cursor MCP (`~/.cursor/mcp.json` or project `.cursor/mcp.json`)

HTTP (server already running):

```json
{
  "mcpServers": {
    "chat-export": {
      "url": "http://127.0.0.1:8765/mcp",
      "headers": {
        "Authorization": "Bearer cem_YOUR_KEY_HERE"
      }
    }
  }
}
```

**Profiles:** expose the full tool surface (`chats_*`, `jobs_*`, `chat_cache_*`, `projects_*`) for IDE agents. A **small** read-focused subset (list/get/export, browsers, platforms) is documented on the [wiki MCP tools page](https://github.com/svergio/chat-export-extension/wiki/MCP-Tools-and-Profiles) — match your client’s token budget. Open WebUI via **mcpo** can proxy the same HTTP endpoint if your setup uses an OpenAPI bridge on another port.

After MCP is configured, run **`browsers_bind`** so tools target your connected Chrome profile.

Extension bridge settings: [chat-export-extension README](https://github.com/svergio/chat-export-extension#configuration).

## Background jobs

Long work (`chat_ask`, export, bulk delete) uses per-browser lanes:

- `jobs_enqueue`, `jobs_status`, `jobs_list`, `jobs_cancel`

## Cursor MCP config

HTTP (server already running):

```json
{
  "mcpServers": {
    "chat-export": {
      "url": "http://127.0.0.1:8765/mcp",
      "headers": {
        "Authorization": "Bearer cek_YOUR_KEY_HERE"
      }
    }
  }
}
```

stdio:

```json
{
  "mcpServers": {
    "chat-export": {
      "command": "chat-export-server",
      "args": ["start", "--stdio"],
      "env": {
        "CHAT_EXPORT_HOME": "/Users/YOU/.chat-export"
      }
    }
  }
}
```

## MCP tools (overview)

| Tool | Purpose |
| --- | --- |
| `browsers_list` / `browsers_bind` / `browsers_status` | Connected Chrome profiles |
| `platforms_list` | Enablement matrix |
| `chats_list` / `chats_get` / `chats_export` | Read and write exports |
| `chats_create` / `chats_delete` | UI drive (delete needs `confirm: true`) |
| `chat_ask` | Send prompt; wait or job queue |
| `jobs_*` | Async pipeline |
| `chat_cache_*` | Temp SQLite cache for long threads |

Full list evolves with releases; see wiki **MCP Tools**.

## Layout

```text
packages/protocol/   wire contract v1
src/core/            config, keys, audit, db, jobs, cache
src/hub/             WebSocket BrowserHub
src/mcp/             MCP HTTP + stdio
src/cli/             CLI entry
src/dashboard-api.ts /dashboard/api + dashboard/public
dashboard/           git submodule → chat-export-dashboard
```

`git submodule update --init` after clone.

## Security

- **Loopback only** by default (`127.0.0.1`). Change host only if you understand exposure.
- Keys (`cek_`/`cem_`) grant full local API — never commit or publish.
- Browser tokens (`ceb_`) are separate from MCP keys.
- `chats_delete` and similar need `allowDestructive` on extension **and** server plus `confirm: true`.
- Append-only **audit** for sensitive RPC. See [SECURITY.md](SECURITY.md).
- Personal data portability is the goal; you must comply with each provider **ToS**. Not legal advice.

## Related repositories

| Repo | Role |
|------|------|
| [chat-export-extension](https://github.com/svergio/chat-export-extension) | Content scripts + WS client |
| [chat-export-server](https://github.com/svergio/chat-export-server) (this) | MCP hub, jobs, cache |
| [chat-export-dashboard](https://github.com/svergio/chat-export-dashboard) | Operator UI submodule |
| [Wiki](https://github.com/svergio/chat-export-extension/wiki) | Install, security, FAQ |

## Support the project

- **Tip (fiat):** [DonationAlerts — svwergio_mel](https://www.donationalerts.com/r/svwergio_mel)

Tips are voluntary; they do not purchase support SLAs or private builds.

## FAQ

- No telemetry; no external servers for core operation.
- Only **your** chats, from **your** browser session.
- Shared wording: [packages/faq.md](packages/faq.md).

## Contributing

See [extension CONTRIBUTING.md](https://github.com/svergio/chat-export-extension/blob/main/CONTRIBUTING.md) (protocol `PLATFORMS`, server MCP, config) and [wiki Contributing](https://github.com/svergio/chat-export-extension/wiki/Contributing).

## License

See [LICENSE](LICENSE).

TDQS

A4/5.0

Scored across 27 tools

Disambiguation3/5

Descriptions do heavy lifting with explicit 'prefer X over Y' guidance, but four different read paths for a chat (chats_get, chat_outline, chat_read, chat_cache_read) plus chat_cache_sync/append/update_block create genuine boundaries an agent must reason through before every read. The explicit legacy duplicate containers_list == projects_list is a hard naming collision, and chats_create vs chat_ask also overlap.

Naming Consistency4/5

Nearly all tools follow namespace_action (browsers_*, projects_*, jobs_*, chats_*), which is predictable and readable. Minor deviations: the chat singleton tools (chat_outline, chat_read, chat_ask, chat_cache_*) use a different prefix than the plural chats_* group, and containers_list sits outside the projects_* namespace it belongs to.

Tool Count3/5

Twenty-seven tools across five real sub-domains (browsers, platforms, chats, cache, projects, jobs) is defensible given the scope, but it is above the comfortable range and forces the agent to triage before acting. At least one slot (containers_list) is pure dead weight, and the three browser tools plus six cache tools could be trimmed.

Completeness4/5

Coverage is unusually thorough: browser lifecycle, provider discovery, chat read/export/create/ask/delete, offline cache CRUD, project CRUD plus chat rehoming, and full async job management with cancel. Gaps are minor: no chats rename/update or metadata patch, no projects rename, and no job retry.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues