Skip to main content
Glama
Kaption-AI

kaption-mcp-remote

Official
by Kaption-AI
README.md
# kaption-mcp-remote

Cloud MCP relay for WhatsApp — lets AI assistants (Claude, ChatGPT, Cursor, etc.) interact with your WhatsApp conversations through the [Model Context Protocol](https://modelcontextprotocol.io/).

**Setup guide:** [kaptionai.com/mcp](https://kaptionai.com/mcp/) — connect WhatsApp to Claude, ChatGPT or Cursor.

**Live at:** [mcp.kaptionai.com](https://mcp.kaptionai.com) (canonical) and
mcp-ext.kaptionai.com (backward-compatible alias for existing connections)

The relay **cannot read your messages**. It forwards MCP tool calls between the AI client and the Kaption browser extension, which processes everything locally in your browser. Its source code is public (BUSL-1.1), so you can verify it yourself.

## Architecture

```
AI Client (Claude/ChatGPT/Cursor)
    │
    │ OAuth 2.1 + SSE/Streamable HTTP
    ▼
┌─────────────────────────────────────┐
│  Cloudflare Worker                  │
│  mcp.kaptionai.com                 │
│                                     │
│  ┌────────────┐  ┌──────────────┐  │
│  │ OAuthProv  │  │ Next.js      │  │
│  │ /sse /mcp  │  │ /authorize   │  │
│  │ /token     │  │ /ext-auth    │  │
│  │ /register  │  │ / (landing)  │  │
│  └─────┬──────┘  └──────────────┘  │
│        │                            │
│  ┌─────▼──────┐  ┌──────────────┐  │
│  │ RelayMCP   │  │ Deployment   │  │
│  │ (DO)       │  │ ChainDO      │  │
│  └─────┬──────┘  └──────────────┘  │
│        │                            │
│  ┌─────▼──────┐                    │
│  │ RelayRoom  │ ◄── WebSocket ──┐  │
│  │ (DO/accountRef) │            │  │
│  └────────────┘                 │  │
└─────────────────────────────────┼──┘
                                  │
                          Browser Extension
                          (WhatsApp Web tab)
```

### Durable Objects

| DO | Keyed By | Purpose |
|----|----------|---------|
| **RelayMCP** | OAuth session | McpAgent — registers tools, relays JSON-RPC to RelayRoom |
| **RelayRoom** | Opaque accountRef | WebSocket bridge to extension, auth handshake, request/response matching |
| **DeploymentChainDO** | `"main"` | Append-only hash chain for deployment transparency |

## Request Flow

1. AI client discovers the MCP server via `/.well-known/oauth-authorization-server`
2. Client registers dynamically via `POST /register` (RFC 7591)
3. User authenticates with WhatsApp OTP at `/authorize`
4. Client exchanges code for token at `/token`
5. Client sends tool calls via SSE (`/sse`) or Streamable HTTP (`/mcp`)
6. **RelayMCP** DO receives the call, routes to **RelayRoom** for the accountRef
7. **RelayRoom** forwards JSON-RPC to the extension over WebSocket
8. Extension executes in WhatsApp Web context, returns result
9. Result flows back: RelayRoom → RelayMCP → AI client

## Routing Table

| Path | Method | Auth | Handler |
|------|--------|------|---------|
| `/` | GET | — | Next.js landing page |
| `/authorize` | GET | — | Next.js OTP form (HMAC-signed oauthReqInfo) |
| `/authorize/send-otp` | POST | — | Next.js API route → rest-api |
| `/authorize/verify` | GET/POST | — | Next.js OTP verify → OAuthProvider completeAuthorization |
| `/authorize/reviewer-login` | POST | Static review credentials | Password completion for the configured synthetic review phone |
| `/register` | POST | — | OAuthProvider (RFC 7591 dynamic client registration) |
| `/token` | POST | — | OAuthProvider (token exchange) |
| `/sse` | GET | OAuth token | RelayMCP DO (SSE transport) |
| `/mcp` | POST | OAuth token | RelayMCP DO (Streamable HTTP) |
| `/ws/ext` | GET | JWT/token in auth msg | RelayRoom DO (WebSocket upgrade) |
| `/ext-auth/*` | Various | — | Next.js extension auth pages + API |
| `/transparency` | GET | — | DeploymentChainDO (chain history) |
| `/transparency/latest` | GET | — | DeploymentChainDO (latest entry) |
| `/transparency/verify` | GET | — | DeploymentChainDO (chain integrity) |
| `/transparency/gaps` | GET | CF token | Cross-reference CF deploys with chain |
| `/transparency/append` | POST | DEPLOY_API_KEY | Append entry (CI only) |

## MCP Tools

16 public tools are forwarded to the extension (the relay does not execute them):

| Tool | Description |
|------|-------------|
| `query` | Query conversations, contacts, messages, transcriptions, labels, communities, sessions |
| `summarize_conversation` | Get or generate a conversation summary |
| `manage_labels` | Add/remove/create/delete WhatsApp Business labels |
| `manage_notes` | Get/set contact notes (Business accounts) |
| `download_media` | Download image/video/audio/document from a message |
| `manage_chat` | Archive, pin, mute, mark read/unread, set/clear draft |
| `manage_reminders` | Create/list/complete/delete personal reminders |
| `manage_scheduled_messages` | Schedule messages for future delivery — from Kaption's number (bot, default) or from your own number on this computer (`mode: "local"`, also to groups) |
| `manage_lists` | Manage personal chat lists (custom categories) |
| `list_contacts`, `get_contact`, `get_contact_groups` | Read contacts and their group memberships |
| `list_groups`, `get_group` | Read cached or live group metadata |
| `export_contacts` | Export contacts as CSV or JSON |
| `get_analytics` | Analyze WhatsApp activity, rankings, response times, and exports |

`get_api_info` is local-only and is deliberately excluded from the cloud
surface because it returns private REST connection credentials.

## Deployment Security

Every deployment is cryptographically signed and recorded in a tamper-evident transparency chain. See [SECURITY.md](./SECURITY.md) for full details.

### Pipeline

```
GitHub Actions (push to main)
    │
    ├─ 1. Run tests
    ├─ 2. Build worker (OpenNext + wrap)
    ├─ 3. SHA-256 manifest every generated code and asset file
    ├─ 4. Pre-deploy: Sigstore sign the manifest → Rekor log
    ├─ 5. Deploy to Cloudflare
    ├─ 6. Post-deploy: verify hash unchanged, sign attestation → Rekor
    └─ 7. Append to transparency chain (hash-linked)
```

Daily heartbeat redeploys (6am UTC) ensure the chain stays active even without code changes.

### Deploys are gated — do NOT run `wrangler deploy` locally

All production deploys go through GitHub Actions. Multiple layers enforce this:

1. `wrangler.jsonc` is gitignored; `scripts/build-config.mjs` renders it from `wrangler.template.jsonc` and refuses to run unless `GITHUB_ACTIONS=true` + `GITHUB_RUN_ID` are set (or `KAPTIONAI_LOCAL_DEV=1` for dev).
2. `npm run predeploy` aborts unless those same CI env vars are present.
3. `main` is branch-protected: requires a reviewed PR + green `test`, `deploy`, and `verify` checks.
4. CODEOWNERS routes every PR through @kshmir.

To ship a change: open a PR → review + CI green → merge to `main` → Actions builds, signs (Sigstore), deploys, and appends to the transparency chain. `npx wrangler deploy` from a laptop will fail at step 1 because there is no `wrangler.jsonc` to deploy.

### Verify a Deployment

```bash
# 1. Check the transparency chain
curl -s https://mcp.kaptionai.com/transparency/latest | jq .

# 2. Verify chain integrity
curl -s https://mcp.kaptionai.com/transparency/verify | jq .

# 3. Verify Sigstore signature (requires cosign)
COMMIT=$(curl -s https://mcp.kaptionai.com/transparency/latest | jq -r '.event.commitSha')
cosign verify-blob \
  --bundle build-manifest.sigstore.json \
  --certificate-identity-regexp "https://github.com/Kaption-AI/mcp-extension-remote/.*" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  build-manifest.json
```

## API Endpoints

### Transparency API (public, no auth)

```bash
# Full chain history (paginated)
GET /transparency?limit=50&offset=0

# Latest deployment
GET /transparency/latest

# Verify chain integrity
GET /transparency/verify
```

### MCP (OAuth-protected)

```bash
# SSE transport (for Claude Code, Cursor)
GET /sse

# Streamable HTTP transport
POST /mcp
```

## Development

```bash
# Install dependencies
npm install

# Run tests
npm test

# Dev server (Next.js only — no Worker routing)
npm run dev

# Build the full worker (OpenNext + custom wrapper)
npm run build:worker
```

### Project Structure

```
src/
  index.ts            # Worker entry — Hono routing, OAuthProvider composition
  relay-mcp.ts        # RelayMCP Durable Object (McpAgent)
  relay-room.ts       # RelayRoom Durable Object (WebSocket bridge)
  deployment-chain.ts # DeploymentChainDO (transparency log)
  otp.ts              # OTP generation, verification, JWT, HMAC, rate limiting
  schemas.ts          # Zod schemas for API request validation
  tools.ts            # MCP tool definitions (forwarded, not executed)
  types.ts            # TypeScript interfaces (Env, DeploymentEvent, etc.)
app/
  page.tsx            # Landing page (multilingual, client-side i18n)
  layout.tsx          # Root layout
  i18n.ts             # i18next init (8 languages)
  locales/            # Translation JSON files
  authorize/          # OAuth OTP flow pages + API routes
  ext-auth/           # Extension auth pages + API routes
scripts/
  wrap-worker.mjs     # Post-build: wraps OpenNext output with custom routing
```

## Environment Variables

### Vars (wrangler.jsonc)

| Variable | Description |
|----------|-------------|
| `INTERNAL_API_BASE_URL` | Backend API base URL |
| `BUILD_HASH` | SHA-256 of worker bundle (set by CI) |
| `COMMIT_SHA` | Git commit SHA (set by CI) |

### Secrets (`wrangler secret put`)

| Secret | Description |
|--------|-------------|
| `INTERNAL_API_KEY` | API key for rest-api OTP endpoint |
| `DEPLOY_API_KEY` | API key for transparency chain append |
| `JWT_SECRET` | Shared JWT signing secret (same as rest-api, schedule, metadata workers) |
| `PHONE_REF_SECRET` | HMAC secret used to derive opaque durable account references from phone numbers |
| `EPHEMERAL_STATE_SECRET` | Encryption secret for short-lived login hints, verify tickets, and encrypted session phone payloads |
| `OPENAI_APPS_CHALLENGE_TOKEN` | Exact domain-verification token issued by the OpenAI plugin portal |
| `OPENAI_REVIEW_PASSWORD_SHA256` | Lowercase SHA-256 hex digest of the high-entropy reviewer password |
| `OPENAI_REVIEW_PHONE` | Phone number used as the dedicated review username and to derive the synthetic account's opaque reference |

The three `OPENAI_*` values are also configured as GitHub Actions repository
secrets. Add all three together, then run the manual **Test, Build & Deploy**
workflow. CI writes them to an ephemeral mode-`0600` file and passes that file
to `wrangler deploy --secrets-file`, so the review configuration ships in the
same signed, attested Worker version as the code. The workflow fails closed if
only part of the three-value set is present and deletes the temporary file
immediately after deployment. Existing Worker secrets not listed in that file
are preserved.

## Related Projects

- **[Kaption Extension](https://kaptionai.com/extension)** — Chrome/Edge/Firefox browser extension (the other side of the relay)
- **[@kaptionai/mcp-extension](https://www.npmjs.com/package/@kaptionai/mcp-extension)** — Local MCP bridge (runs on your machine, no cloud relay)

## License

[BUSL-1.1](./LICENSE)