Meta Business Mcp

Created By
metabusiness-mcp3 hours ago
Meta Business MCP is a production-validated MCP server for the WhatsApp Business Cloud API. It sits between your AI agent and Meta's API as a compliance gate — validating 24-hour care windows, opt-out status, frequency caps, and rate limits in under 2ms before any message is sent. Exposes 24 structured tools covering messaging, campaigns, templates, and error intelligence. Built in Go, backed by PostgreSQL, Redis, and NATS JetStream. Validated against real Meta Graph API v20.0 production traffic with 85.6% test coverage.
Overview

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

  1. Why This Exists
  2. What It Does
  3. Quick Start
  4. MCP Tools
  5. Architecture
  6. Configuration
  7. Testing
  8. Deployment
  9. Business Model
  10. Roadmap
  11. Observability
  12. Documentation Index
  13. Contributing
  14. License

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

ResponsibilityDescription
Compliance GateEvaluates every outbound message against Meta's care window rules, opt-out lists, and frequency caps before delivery.
Policy EnforcementApplies custom business policies (time boundaries, segment exclusions, VIP tag overrides) from a YAML-seeded database.
Async Message DeliveryQueues messages to NATS JetStream and dispatches them via a worker pool with automatic retries and exponential backoff.
Rate LimitingEnforces per-customer token-bucket rate limits via Redis Lua scripts.
Error IntelligenceTranslates numeric Meta API error codes into categorized, actionable developer instructions.
Campaign ManagementSchedule, pause, cancel campaigns with audience segmentation and template validation.
Template LifecycleCreate, sync, and validate templates via Meta API with local persistence.
MCP ServerExposes 24 structured tools to AI Agents over stdio using the Model Context Protocol.
Webhook ReceiverProcesses 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 --build

Wait 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
# OK

What 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

ToolDescriptionTierStatus
check_compliance()Evaluate if a planned outbound message complies with Meta rules and local policies[All]
send_message()Send free-form service text message (requires active 24h care window)[All]
send_template()Send approved template message (bypasses 24h care window)[All]
explain_error()Translate Meta API error code into categorized, actionable explanation[All]
reply_customer()Reply within an active conversation context (requires open 24h window)[All]
retry_failed_messages()Trigger manual retry for one or more failed messages with retryability validation[All]
sync_template_status()Sync template approval status from Meta API and update local database[All]

Read-Only Intelligence

ToolDescriptionTierStatus
check_conversation()Query conversation window status, time remaining, type, and eligibility[All]
check_frequency_cap()Check if a customer is under Meta's frequency cap for marketing messages[All]
get_customer_context()Retrieve full customer profile: opt-in/out, tags, engagement score, eligibility[All]
get_delivery_status()Query message delivery status (sent/delivered/read/failed) with error intelligence[All]
get_rate_limit()Query current MPS capacity, tokens consumed, and tokens remaining[All]
list_conversations()List conversations with filters: open, closed, expiring_soon[All]
list_templates()List templates with status/category/locale filters from Meta API[All]

Scheduling & Campaign

ToolDescriptionTierStatus
schedule_message()Schedule single message for future delivery with compliance pre-check[All]
schedule_campaign()Schedule broadcast campaign with approved template and audience filter[Pro]
cancel_campaign()Cancel campaign in non-terminal state (scheduled/running/paused)[Pro]
pause_campaign()Pause active campaign, preserving progress counters for resume[Pro]

Account & Cost Intelligence

ToolDescriptionTierStatus
get_account_quality()Retrieve WABA quality score and messaging limit tier from Meta[All]
estimate_cost()Estimate conversation cost for a planned message batch[All]
estimate_pricing()Query current conversation pricing tier for country/type combination[All]

Operational

ToolDescriptionTierStatus
create_template()Submit new template to Meta for approval, persist locally as PENDING[All]
sync_webhooks()Trigger manual re-sync of template statuses and pending webhook events[All]
archive_chat()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:

ModeTransportPurpose
MCP Serverstdio (stdin/stdout)Exposes 24 structured tools to AI clients (Gemini, Claude, Cursor)
HTTP ServerTCP :8080Webhook 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

ServicePackageRole
MCP Serverpkg/mcp/Registers and handles 24 MCP tool calls from AI Agents. Split into 6 handler files (~2,000 lines).
Compliance Enginepkg/compliance/Enforces the 24h care window, opt-out/opt-in state, and frequency caps.
Policy Enginepkg/policy/Evaluates dynamic business rules (time limits, tag exclusions) from the DB.
Conversation State Enginepkg/state/Manages care window TTL with Redis caching and PostgreSQL fallback.
User Intelligencepkg/userintel/Tracks opt-ins, tags (e.g. vip), and interaction timelines.
Template Managerpkg/template/Syncs approved templates from Meta, validates variables, caches locally.
Delivery Orchestratorpkg/delivery/Enqueues messages to NATS JetStream; manages the background worker pool.
Schedulerpkg/delivery/In-process poll-based scheduler for scheduled messages and campaigns.
Rate Limiterpkg/ratelimit/Per-customer token bucket rate limits via Redis Lua scripts.
Error Intelligencepkg/errorintel/Maps Meta error codes to retry/no-retry classifications and explanations.
Campaign Modulepkg/campaign/Campaign schema, audience filters, and tier-gated operations.
Webhook Receiverpkg/webhook/Parses and dispatches inbound Meta events (messages, status, templates).
Observabilitypkg/observability/Custom Prometheus metrics.

Persistence Layers

LayerTechnologyUsage
Primary DBPostgreSQL 16 (pgxpool)All persistent data: conversations, messages, customers, templates, policies, campaigns, audit logs.
CacheRedis 7Care window TTL state; token-bucket counters via Lua scripts; graceful PG fallback.
Message BrokerNATS JetStreamAsync 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

StreamSubjectsConsumerMax DeliverAck WaitBackoff
META_MCP_DELIVERYwhatsapp.messages.outbound, whatsapp.messages.retrydelivery-workers (durable pull)330s1s → 5s (NakWithDelay)
META_MCP_CAMPAIGNwhatsapp.campaigns.triggercampaign-workers

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 | enterprise

Environment Variables

All config values can be overridden with environment variables. Required values are marked with ✅.

VariableDefaultRequiredDescription
SERVER_HTTP_PORT8080HTTP server port
SERVER_MCP_NAME"meta-business-mcp"MCP server identifier
SERVER_MCP_VERSION"1.0.0"MCP server version string
DB_HOST"localhost"PostgreSQL host
DB_PORT5432PostgreSQL port
DB_USER"postgres"PostgreSQL username
DB_PASSWORD"password"PostgreSQL password
DB_NAME"meta_mcp"PostgreSQL database name
DB_SSLMODE"disable"disable, require, or verify-ca
REDIS_ADDR"localhost:6379"Redis connection address
REDIS_PASSWORD""Redis auth password
REDIS_DB0Redis database index
NATS_URL"nats://localhost:4222"NATS connection URL
META_API_URL"https://graph.facebook.com"Meta Graph API base URL
META_ACCESS_TOKENMeta API OAuth token (system user)
META_PHONE_NUMBER_IDWhatsApp Business Phone Number ID
META_WABA_IDWhatsApp Business Account ID
META_WEBHOOK_VERIFY_TOKENMeta webhook verification passphrase
POLICIES_PATH"policies.yaml"Path to the business policy seed YAML file
TIER"oss"Feature tier: oss, pro, or enterprise
SCHEDULER_POLL_INTERVAL"30s"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)

PackageCoverage
pkg/compliance93.9%
pkg/errorintel100.0%
pkg/config96.2%
pkg/observability100.0%
pkg/ratelimit87.5%
pkg/webhook83.6%
pkg/state83.3%
pkg/userintel82.1%
pkg/policy79.5%
pkg/template78.9%
pkg/campaign77.1%
pkg/delivery73.8%
pkg/mcp61.6%

Test Suites

SuiteFileTestsStatus
v1 Handlerspkg/mcp/server_test.go5 (check_compliance, explain_error, send_message, send_template, phone normalization)
Group A — Intelligencepkg/mcp/server_test.go8 (check_conversation, check_frequency_cap, get_customer_context, get_delivery_status ×2, get_rate_limit, list_templates, list_conversations)
Group B — Messagingpkg/mcp/server_test.go5 (reply_customer ×2, retry_failed_messages ×2, sync_template_status)
Group C — Campaignpkg/mcp/server_test.go5 (schedule_message ×2, campaign tier-gating ×3)
Group D — Accountpkg/mcp/server_test.go4 (estimate_cost, estimate_pricing, get_account_quality)
Group E — Opspkg/mcp/server_test.go3 (archive_chat ×2, sync_webhooks)
Schedulerpkg/delivery/scheduler_test.go5 (due message, future message, compliance failure, duplicate dispatch, campaign trigger)
Integrationtests/integration_test.go7
E2Etests/e2e_test.go3
Failure Simulationtests/failure_test.go4 (Redis outage, NATS outage, Meta 500, Meta 131049)

Benchmark Result

ToolLatencyvs. Target
check_compliance()1.69 ms~30× faster than 50ms target

Deployment

Build the Binary

go build -o mcp-server ./cmd/server/main.go

Production 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=30s

Production 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 --build

Database Migrations & Seeding

No external migration runner is required. On startup, the application automatically:

  1. Creates all database tables (customers, conversations, messages, templates, policies, campaigns, message_frequencies, error_knowledge_base, audit_logs, conversation_pricing).
  2. Seeds standard Meta error codes into error_knowledge_base.
  3. Seeds business policies from policies.yaml using idempotent ON CONFLICT DO UPDATE.
  4. 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 with hub.challenge.
  • Events: POST /webhook — receives inbound messages, status updates, and template events.
  • Signature validation: X-Hub-Signature-256 header is verified on all POST events.

Infrastructure Dependencies

DependencyMinimum VersionNotes
PostgreSQL16AWS RDS compatible
Redis7AWS ElastiCache compatible
NATS ServerLatest stableMust enable JetStream (--jetstream)
Go1.21+Build only
Docker20.10+Compose V2 required

Business Model

TierPriceWABAsMessagesFeatures
OSSFree1200/dayCompliance engine, basic messaging, read-only intelligence
Pro$149/moUp to 5UnlimitedFull MCP tool suite, campaign management, scheduling, dashboard
Enterprise$499/moUnlimitedUnlimitedDedicated 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

PhaseMilestoneStatus
Phase 1v1.0 — Core Platform (4 tools)✅ Complete
Phase 2Sprint 2 — MCP Tool Completion (4→24 tools)✅ Complete
Phase 3Tool Rename + PRD Update✅ Complete
Phase 4Operational Dashboard (Next.js + go:embed)✅ Complete
Phase 5Managed Cloud MVP (Railway, Stripe billing)Next (Weeks 3-6)
Phase 6Design Partner Validation (3-5 agencies beta)Weeks 5-10
Phase 7Commercial Launch ($149 Pro / $499 Enterprise)Weeks 9-12
Phase 8Scale (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

EndpointMethodResponse
/healthGET200 OK — body: "OK"
/metricsGET200 OK — Prometheus scrape payload
/webhookGET200 OK — webhook challenge echo
/webhookPOST200 OK — body: "EVENT_RECEIVED"

Health Check

curl http://localhost:8080/health

Prometheus Metrics

curl http://localhost:8080/metrics

Custom 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 app

NATS Monitoring

NATS monitoring HTTP interface is available at :8222. Stream and consumer stats: http://localhost:8222/jsz.


Documentation Index

DocumentDescription
docs/architecture.mdComponent layout, DB schema (ER), NATS stream topology, Redis caching strategy
docs/api_reference.mdHTTP endpoint specs + all 24 MCP tool specifications with request/response examples
docs/deployment_guide.mdStep-by-step production deployment, Docker Compose templates, migrations
docs/developer_guide.mdHow to add policies, register new MCP tools, extend NATS queue workers
docs/env_variables.mdComplete environment variable reference table
docs/limitations.mdKnown platform limits and future roadmap
docs/mcp-tools-test-report.mdIntegration test report for all 24 MCP tools
walkthrough-1.mdMVP implementation summary
walkthrough-2.mdPhase 6: Harden & Document — testing, benchmarks, documentation sprint
walkthrough-3.mdWABA production validation, regression fixes, boundary normalization
walkthrough-4.mdSprint 2: MCP Tool Completion (4→24 tools) — architecture decisions, test coverage
PRD_MetaBusinessMCP.mdProduct Requirements Document v3.2

Contributing

This project uses Go 1.21+, PostgreSQL 16, Redis 7, and NATS JetStream.

  1. Fork the repository.
  2. Create a feature branch: git checkout -b feature/my-change
  3. Run tests before submitting: go test -count=1 -p 1 ./...
  4. 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

Server Config

{
  "mcpServers": {
    "meta-business-mcp": {
      "command": "/path/to/meta-business-mcp",
      "args": [],
      "env": {
        "CONFIG_PATH": "/path/to/config.yaml"
      }
    }
  }
}
Project Info
Created At
3 hours ago
Updated At
3 hours ago
Author Name
metabusiness-mcp
Star
-
Language
-
License
-
Category

Recommend Servers

View All
Tavily Mcp
@tavily-ai

JavaScript
a year ago
The Texas Voice

18 hours ago