Meta Business MCP
Integrates with Meta's Cloud API to enforce WhatsApp Business compliance policies, handle webhook events, and manage account quality and pricing for WhatsApp messaging.
Provides compliance-gated messaging, template management, campaign scheduling, and conversation state tracking for WhatsApp Business, enabling AI agents to send and manage messages safely within Meta's rules.
Meta Business MCP
Go 1.21+ License: Apache 2.0 Tests: Passing Coverage: 85.6% Tools: 24 Production-Validated
A WhatsApp compliance intelligence platform that ensures every AI Agent can operate WhatsApp Business safely, compliantly, and production-ready — without understanding Meta's rule complexity.
For: AI Agent developers · Digital agencies · WhatsApp automation teams 21 tools free forever · 3 campaign tools on Pro
Table of Contents
Related MCP server: whatsapp-mcp-server
Why This Exists
AI Agents don't understand Meta's WhatsApp Business rules — 24-hour care windows, frequency caps, template categories, opt-out mandates, rate limits. Sending a single message wrong means account suspension, message rejection, and compliance violations. Meta Business MCP sits between the AI Agent and Meta's API, enforcing every rule automatically so the Agent never has to learn them.
What It Does
Responsibility | Description |
Compliance Gate | Evaluates every outbound message against Meta's care window rules, opt-out lists, and frequency caps before delivery. |
Policy Enforcement | Applies custom business policies (time boundaries, segment exclusions, VIP tag overrides) from a YAML-seeded database. |
Async Message Delivery | Queues messages to NATS JetStream and dispatches them via a worker pool with automatic retries and exponential backoff. |
Rate Limiting | Enforces per-customer token-bucket rate limits via Redis Lua scripts. |
Error Intelligence | Translates numeric Meta API error codes into categorized, actionable developer instructions. |
Campaign Management | Schedule, pause, cancel campaigns with audience segmentation and template validation. |
Template Lifecycle | Create, sync, and validate templates via Meta API with local persistence. |
MCP Server | Exposes 24 structured tools to AI Agents over stdio using the Model Context Protocol. |
Webhook Receiver | Processes inbound events from Meta: customer messages, delivery status updates, and template approval callbacks. |
Quick Start
1. Clone and Start
git clone https://github.com/metabusiness-mcp/meta-business-mcp.git
cd meta-business-mcp
docker compose up -d --buildWait for all containers to become healthy:
docker compose ps
# All should show "healthy"2. Access the Dashboard
Open your browser: http://localhost:8080
On first run, the server auto-generates a random password and prints it to the terminal:
╔══════════════════════════════════════════════════════════╗
║ DASHBOARD CREDENTIALS (auto-generated) ║
╠══════════════════════════════════════════════════════════╣
║ Username: admin ║
║ Password: a1b2c3d4e5f6g7h8 ║
╚══════════════════════════════════════════════════════════╝Copy the password and log in.
3. Connect Your AI Agent
The MCP server runs on stdio. Configure your AI client (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"meta-business-mcp": {
"command": "/path/to/meta-business-mcp",
"args": []
}
}
}4. Verify
curl http://localhost:8080/health
# OKWhat starts: PostgreSQL 16 (:5432), Redis 7 (:6379), NATS JetStream (:4222), Mock Meta API (:8081), Meta Business MCP (:8080 + MCP stdio). Mock credentials are used by default — no Meta API keys required for local development.
MCP Tools
All 24 tools are exposed to AI Agents over stdio using the Model Context Protocol. All tools are production-ready and validated against real WABA production (Meta Graph API v20.0).
Action Operations
Tool | Description | Tier | Status |
| Evaluate if a planned outbound message complies with Meta rules and local policies | [All] | ✅ |
| Send free-form service text message (requires active 24h care window) | [All] | ✅ |
| Send approved template message (bypasses 24h care window) | [All] | ✅ |
| Translate Meta API error code into categorized, actionable explanation | [All] | ✅ |
| Reply within an active conversation context (requires open 24h window) | [All] | ✅ |
| Trigger manual retry for one or more failed messages with retryability validation | [All] | ✅ |
| Sync template approval status from Meta API and update local database | [All] | ✅ |
Read-Only Intelligence
Tool | Description | Tier | Status |
| Query conversation window status, time remaining, type, and eligibility | [All] | ✅ |
| Check if a customer is under Meta's frequency cap for marketing messages | [All] | ✅ |
| Retrieve full customer profile: opt-in/out, tags, engagement score, eligibility | [All] | ✅ |
| Query message delivery status (sent/delivered/read/failed) with error intelligence | [All] | ✅ |
| Query current MPS capacity, tokens consumed, and tokens remaining | [All] | ✅ |
| List conversations with filters: open, closed, expiring_soon | [All] | ✅ |
| List templates with status/category/locale filters from Meta API | [All] | ✅ |
Scheduling & Campaign
Tool | Description | Tier | Status |
| Schedule single message for future delivery with compliance pre-check | [All] | ✅ |
| Schedule broadcast campaign with approved template and audience filter | [Pro] | ✅ |
| Cancel campaign in non-terminal state (scheduled/running/paused) | [Pro] | ✅ |
| Pause active campaign, preserving progress counters for resume | [Pro] | ✅ |
Account & Cost Intelligence
Tool | Description | Tier | Status |
| Retrieve WABA quality score and messaging limit tier from Meta | [All] | ✅ |
| Estimate conversation cost for a planned message batch | [All] | ✅ |
| Query current conversation pricing tier for country/type combination | [All] | ✅ |
Operational
Tool | Description | Tier | Status |
| Submit new template to Meta for approval, persist locally as PENDING | [All] | ✅ |
| Trigger manual re-sync of template statuses and pending webhook events | [All] | ✅ |
| Archive conversation in terminal state (expired window) | [All] | ✅ |
Full parameter specifications and response examples: docs/api_reference.md
Architecture
Dual-Mode Binary
The platform compiles to a single Go binary that runs two servers concurrently:
Mode | Transport | Purpose |
MCP Server | stdio (stdin/stdout) | Exposes 24 structured tools to AI clients (Gemini, Claude, Cursor) |
HTTP Server | TCP :8080 | Webhook receiver, health checks, Prometheus metrics |
High-Level Component Diagram
┌───────────────────────────────┐
│ AI Agent │
└──────────────┬────────────────┘
│ Stdio (MCP Protocol)
▼
┌────────────────────────────────────────────────────────┐
│ Meta Business MCP │
│ │
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ MCP Server ├───────►│ Compliance Engine │ │
│ └───────────────────┘ └─────────┬─────────┘ │
│ ▼ │
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ Webhook Receiver │ │ Policy Engine │ │
│ └─────────▲─────────┘ └─────────┬─────────┘ │
│ │ ▼ │
│ │ ┌───────────────────┐ │
│ │ │ Orchestrator │ │
│ │ └─────────┬─────────┘ │
└─────────────┼────────────────────────────┼─────────────┘
│ Webhook │ POST /messages
│ ▼
┌─────────────┴────────────────────────────┴─────────────┐
│ Meta Cloud API (or Mock :8081) │
└────────────────────────────────────────────────────────┘Core Services
Service | Package | Role |
MCP Server |
| Registers and handles 24 MCP tool calls from AI Agents. Split into 6 handler files (~2,000 lines). |
Compliance Engine |
| Enforces the 24h care window, opt-out/opt-in state, and frequency caps. |
Policy Engine |
| Evaluates dynamic business rules (time limits, tag exclusions) from the DB. |
Conversation State Engine |
| Manages care window TTL with Redis caching and PostgreSQL fallback. |
User Intelligence |
| Tracks opt-ins, tags (e.g. |
Template Manager |
| Syncs approved templates from Meta, validates variables, caches locally. |
Delivery Orchestrator |
| Enqueues messages to NATS JetStream; manages the background worker pool. |
Scheduler |
| In-process poll-based scheduler for scheduled messages and campaigns. |
Rate Limiter |
| Per-customer token bucket rate limits via Redis Lua scripts. |
Error Intelligence |
| Maps Meta error codes to retry/no-retry classifications and explanations. |
Campaign Module |
| Campaign schema, audience filters, and tier-gated operations. |
Webhook Receiver |
| Parses and dispatches inbound Meta events (messages, status, templates). |
Observability |
| Custom Prometheus metrics. |
Persistence Layers
Layer | Technology | Usage |
Primary DB | PostgreSQL 16 ( | All persistent data: conversations, messages, customers, templates, policies, campaigns, audit logs. |
Cache | Redis 7 | Care window TTL state; token-bucket counters via Lua scripts; graceful PG fallback. |
Message Broker | NATS JetStream | Async delivery queue with WorkQueue retention and pull consumers. |
Database Schema (ER Diagram)
erDiagram
customers ||--o{ conversations : has
conversations ||--o{ messages : contains
templates ||--o{ messages : sent_as
messages }|--o{ message_frequencies : logs
customers {
varchar id PK "Phone Number"
varchar channel
boolean opt_in_marketing
boolean opt_in_utility
timestamp last_interaction_at
double engagement_score
text_array tags
}
conversations {
uuid id PK
varchar customer_id FK
varchar channel
timestamp last_inbound_at
timestamp last_outbound_at
timestamp window_expires_at
varchar conversation_type
varchar active_template_id
varchar status "active/archived"
}
messages {
varchar id PK "Meta Message ID or UUID"
uuid conversation_id FK
varchar customer_id FK
varchar direction "inbound/outbound"
varchar message_type "text/template"
jsonb content
varchar status "queued/sent/delivered/read/failed/scheduled"
integer error_code
text error_message
integer retry_count
timestamp next_retry_at
timestamp deliver_at "nullable, for scheduled messages"
}
templates {
varchar name PK
varchar locale PK
varchar category "marketing/utility"
varchar status
text body_text
jsonb variables
}
policies {
varchar id PK
varchar name
varchar type
varchar channel
varchar message_type
boolean is_enabled
jsonb rules
}
error_knowledge_base {
integer code PK
varchar category
boolean can_retry
text human_explanation
text suggested_action
}
audit_logs {
uuid id PK
varchar action
jsonb details
timestamp created_at
}NATS JetStream Queue Topology
Stream | Subjects | Consumer | Max Deliver | Ack Wait | Backoff |
|
|
| 3 | 30s | 1s → 5s ( |
|
|
| — | — | — |
Redis Caching Strategy
Cache Key Pattern:
conv:<customer_id>:<channel>(e.g.conv:628119989630:whatsapp)TTL: Dynamically set to the exact remaining duration of the 24-hour care window.
Graceful Fallback: If Redis is offline, the state engine falls back to PostgreSQL without error — validated by failure simulation tests.
Phone Number Format: Internal cache and DB store numbers without the leading
+prefix. MCP tool boundaries normalize+-prefixed inputs.
Channel-agnostic architecture. WhatsApp is the active channel. Messenger and Instagram are activation targets, not roadmap commitments.
Full architecture documentation: docs/architecture.md
Configuration
Config File (config.yaml)
Place config.yaml in the project root for local development:
server:
http_port: 8080
mcp_name: "meta-business-mcp"
mcp_version: "1.0.0"
database:
host: "localhost"
port: 5432
user: "postgres"
password: "password"
dbname: "meta_mcp"
sslmode: "disable"
redis:
addr: "localhost:6379"
nats:
url: "nats://localhost:4222"
meta:
api_url: "http://localhost:8081" # Use mock server for offline dev
phone_number_id: "mock-phone-id"
waba_id: "mock-waba-id"
access_token: "mock-access-token"
webhook_verify_token: "mock-verify-token"
policies_path: "policies.yaml"
tier: "oss" # oss | pro | enterpriseEnvironment Variables
All config values can be overridden with environment variables. Required values are marked with ✅.
Variable | Default | Required | Description |
|
| — | HTTP server port |
|
| — | MCP server identifier |
|
| — | MCP server version string |
|
| — | PostgreSQL host |
|
| — | PostgreSQL port |
|
| — | PostgreSQL username |
|
| — | PostgreSQL password |
|
| — | PostgreSQL database name |
|
| — |
|
|
| — | Redis connection address |
|
| — | Redis auth password |
|
| — | Redis database index |
|
| — | NATS connection URL |
|
| — | Meta Graph API base URL |
| — | ✅ | Meta API OAuth token (system user) |
| — | ✅ | WhatsApp Business Phone Number ID |
| — | ✅ | WhatsApp Business Account ID |
| — | ✅ | Meta webhook verification passphrase |
|
| — | Path to the business policy seed YAML file |
|
| — | Feature tier: |
|
| — | Scheduler polling interval for scheduled messages/campaigns |
Business Policies (policies.yaml)
Business policies are seeded from policies.yaml on startup and stored in the policies table. The seed script is idempotent (ON CONFLICT DO UPDATE), so restarting the app is sufficient to apply changes.
- id: "no_marketing_after_8pm"
name: "No marketing after 8pm"
type: "time_restriction"
channel: "whatsapp"
message_type: "marketing"
is_enabled: true
rules:
deny_after: "20:00"
timezone: "Asia/Jakarta"Full environment variable reference: docs/env_variables.md
Testing
Run All Tests
go test -count=1 -p 1 -cover ./...Run Compliance Benchmark
go test -bench=BenchmarkCheckCompliance -benchtime=5s ./pkg/compliance/Package Coverage (Sprint 2)
Package | Coverage |
| 93.9% |
| 100.0% |
| 96.2% |
| 100.0% |
| 87.5% |
| 83.6% |
| 83.3% |
| 82.1% |
| 79.5% |
| 78.9% |
| 77.1% |
| 73.8% |
| 61.6% |
Test Suites
Suite | File | Tests | Status |
v1 Handlers |
| 5 (check_compliance, explain_error, send_message, send_template, phone normalization) | ✅ |
Group A — Intelligence |
| 8 (check_conversation, check_frequency_cap, get_customer_context, get_delivery_status ×2, get_rate_limit, list_templates, list_conversations) | ✅ |
Group B — Messaging |
| 5 (reply_customer ×2, retry_failed_messages ×2, sync_template_status) | ✅ |
Group C — Campaign |
| 5 (schedule_message ×2, campaign tier-gating ×3) | ✅ |
Group D — Account |
| 4 (estimate_cost, estimate_pricing, get_account_quality) | ✅ |
Group E — Ops |
| 3 (archive_chat ×2, sync_webhooks) | ✅ |
Scheduler |
| 5 (due message, future message, compliance failure, duplicate dispatch, campaign trigger) | ✅ |
Integration |
| 7 | ✅ |
E2E |
| 3 | ✅ |
Failure Simulation |
| 4 (Redis outage, NATS outage, Meta 500, Meta 131049) | ✅ |
Benchmark Result
Tool | Latency | vs. Target |
| 1.69 ms | ~30× faster than 50ms target |
Deployment
Build the Binary
go build -o mcp-server ./cmd/server/main.goProduction Environment (.env)
SERVER_HTTP_PORT=8080
SERVER_MCP_NAME=meta-business-mcp
SERVER_MCP_VERSION=1.0.0
TIER=oss
DB_HOST=postgres.prod.internal
DB_PORT=5432
DB_USER=mcp_user
DB_PASSWORD=production_secure_postgres_pass
DB_NAME=meta_mcp
DB_SSLMODE=require
REDIS_ADDR=redis.prod.internal:6379
REDIS_PASSWORD=production_redis_auth_pass
REDIS_DB=0
NATS_URL=nats://nats.prod.internal:4222
META_API_URL=https://graph.facebook.com
META_ACCESS_TOKEN=EAAG...production_long_lived_system_user_token...
META_PHONE_NUMBER_ID=106555123456789
META_WABA_ID=204555123456789
META_WEBHOOK_VERIFY_TOKEN=production_webhook_verification_passphrase
POLICIES_PATH=/app/policies.yaml
SCHEDULER_POLL_INTERVAL=30sProduction Docker Compose
services:
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_USER: mcp_user
POSTGRES_PASSWORD: production_secure_postgres_pass
POSTGRES_DB: meta_mcp
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mcp_user -d meta_mcp"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: always
command: redis-server --requirepass production_redis_auth_pass
volumes:
- redisdata:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "production_redis_auth_pass", "ping"]
interval: 10s
timeout: 5s
retries: 5
nats:
image: nats:alpine
restart: always
command: "--jetstream -m 8222"
ports:
- "4222:4222"
volumes:
- natsdata:/data
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "4222"]
interval: 10s
timeout: 5s
retries: 5
app:
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- "8080:8080"
env_file:
- .env
volumes:
- ./policies.yaml:/app/policies.yaml
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
nats:
condition: service_healthy
volumes:
pgdata:
redisdata:
natsdata:docker compose -f docker-compose.prod.yaml up -d --buildDatabase Migrations & Seeding
No external migration runner is required. On startup, the application automatically:
Creates all database tables (
customers,conversations,messages,templates,policies,campaigns,message_frequencies,error_knowledge_base,audit_logs,conversation_pricing).Seeds standard Meta error codes into
error_knowledge_base.Seeds business policies from
policies.yamlusing idempotentON CONFLICT DO UPDATE.Seeds conversation pricing data for ID, US, IN, BR, GB, and DEFAULT fallback.
All schema changes use IF NOT EXISTS / ADD COLUMN IF NOT EXISTS. Existing deployments upgrade by restarting the application.
Webhook Registration
Register the public URL in the Meta App Developer Portal:
Verification:
GET /webhook— responds withhub.challenge.Events:
POST /webhook— receives inbound messages, status updates, and template events.Signature validation:
X-Hub-Signature-256header is verified on all POST events.
Infrastructure Dependencies
Dependency | Minimum Version | Notes |
PostgreSQL | 16 | AWS RDS compatible |
Redis | 7 | AWS ElastiCache compatible |
NATS Server | Latest stable | Must enable JetStream ( |
Go | 1.21+ | Build only |
Docker | 20.10+ | Compose V2 required |
Business Model
Tier | Price | WABAs | Messages | Features |
OSS | Free | 1 | 200/day | Compliance engine, basic messaging, read-only intelligence |
Pro | $149/mo | Up to 5 | Unlimited | Full MCP tool suite, campaign management, scheduling, dashboard |
Enterprise | $499/mo | Unlimited | Unlimited | Dedicated infrastructure, SSO, custom policies, SLA |
Campaign operations (schedule_campaign, cancel_campaign, pause_campaign) are gated behind the Pro tier.
Licensed under Apache 2.0.
Roadmap
Phase | Milestone | Status |
Phase 1 | v1.0 — Core Platform (4 tools) | ✅ Complete |
Phase 2 | Sprint 2 — MCP Tool Completion (4→24 tools) | ✅ Complete |
Phase 3 | Tool Rename + PRD Update | ✅ Complete |
Phase 4 | Operational Dashboard (Next.js + go:embed) | ✅ Complete |
Phase 5 | Managed Cloud MVP (Railway, Stripe billing) | Next (Weeks 3-6) |
Phase 6 | Design Partner Validation (3-5 agencies beta) | Weeks 5-10 |
Phase 7 | Commercial Launch ($149 Pro / $499 Enterprise) | Weeks 9-12 |
Phase 8 | Scale (15-20 paying customers) | Month 4-6 |
Messenger and Instagram are out of scope until funded. No roadmap commitment exists for these channels.
Full roadmap details: PRD_MetaBusinessMCP.md §27
Observability
HTTP Endpoints
Endpoint | Method | Response |
|
|
|
|
|
|
|
|
|
|
|
|
Health Check
curl http://localhost:8080/healthPrometheus Metrics
curl http://localhost:8080/metricsCustom metrics are registered in pkg/observability/. Standard Go runtime and process metrics are included automatically via the default Prometheus registry.
Logging
Structured logs are written to stdout/stderr. Collect via Docker:
docker compose logs -f appNATS Monitoring
NATS monitoring HTTP interface is available at :8222. Stream and consumer stats: http://localhost:8222/jsz.
Documentation Index
Document | Description |
Component layout, DB schema (ER), NATS stream topology, Redis caching strategy | |
HTTP endpoint specs + all 24 MCP tool specifications with request/response examples | |
Step-by-step production deployment, Docker Compose templates, migrations | |
How to add policies, register new MCP tools, extend NATS queue workers | |
Complete environment variable reference table | |
Known platform limits and future roadmap | |
Integration test report for all 24 MCP tools | |
MVP implementation summary | |
Phase 6: Harden & Document — testing, benchmarks, documentation sprint | |
WABA production validation, regression fixes, boundary normalization | |
Sprint 2: MCP Tool Completion (4→24 tools) — architecture decisions, test coverage | |
Product Requirements Document v3.2 |
Contributing
This project uses Go 1.21+, PostgreSQL 16, Redis 7, and NATS JetStream.
Fork the repository.
Create a feature branch:
git checkout -b feature/my-changeRun tests before submitting:
go test -count=1 -p 1 ./...Submit a pull request with a clear description of the change.
See docs/developer_guide.md for extending policies, adding MCP tools, and working with the queue worker architecture.
License
Apache License 2.0
Copyright 2026 Adam Zibran
This server cannot be installed
Maintenance
Latest Blog Posts
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/metabusiness-mcp/meta-business-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server