Skip to Content
WhatsApp MCPDevelopmentLocal Setup

Local development setup

Walk-through to go from git clone to a running stdio MCP server with one tool (ping).

1. Prerequisites

  • Node 20+. node --version.
  • pnpm. Activate via corepack:
    corepack enable corepack prepare pnpm@9 --activate
  • Docker. Used to run Postgres locally and by integration tests (testcontainers).

2. Clone + install

git clone <repo-url> whatsapp-mcp cd whatsapp-mcp pnpm install

3. Env

cp .env.example .env

For Phase 1 you only need DATABASE_URL. The default in .env.example matches the dev docker compose:

DATABASE_URL=postgres://wa:wa@localhost:5432/wa_mcp

Every other secret (Meta, Inngest, media signing) can be left blank until the phase that needs it.

4. Postgres

docker compose -f docker-compose.dev.yml up -d

Wait for pg_isready (a few seconds). Then:

pnpm db:migrate

This applies drizzle/0001_init.sql and creates drizzle_migrations to track future migrations.

5. Seed the owner row

pnpm seed:owner

Copy the printed UUID into .env as LOCAL_OWNER_CLIENT_ID. (Phase 4 needs this; Phase 1 doesn’t strictly require it, but you’ll want it set before you forget.)

6. Run the MCP server

pnpm dev

You should see mcp:stdio ready on stderr. The server is now reading JSON-RPC from stdin.

7. Talk to it from Claude Code

Add an MCP server entry (location varies by OS — see Claude Code docs):

{ "command": "pnpm", "args": ["-C", "/absolute/path/to/whatsapp-mcp", "dev"], "env": { "MCP_TRANSPORT": "stdio" } }

Restart Claude Code. The ping tool should appear; calling it should return { ok, ts, version }.

8. Run tests

pnpm test # unit pnpm test:integration # spins up Postgres testcontainer pnpm test:ci # full + coverage

Troubleshooting

  • Invalid environment configurationpnpm dev failed on env validation. The error lists each invalid key on its own line; fix .env and re-run.
  • ECONNREFUSED 127.0.0.1:5432 — Postgres isn’t up. docker compose -f docker-compose.dev.yml ps.
  • Migrations stall on first run — Postgres may not be ready yet. docker compose -f docker-compose.dev.yml logs postgres to confirm.
  • ESLint complains about process.env — that’s the local/no-process-env-outside-config rule firing. Move the read into src/config/env.ts and import the typed config object.