Developer Guide
How to extend policies, register new MCP tools, and add NATS queue workers.
This guide describes how to extend the Meta Business MCP platform, including adding new policies, creating new MCP tools, and registering new message queues.
1. Adding New Policies
The Policy Engine (pkg/policy/policy.go) evaluates business rules dynamically seeded from the database.
To add a new policy type:
Define the Policy Schema
Add the policy rules configuration to policies.yaml (or database directly). For example, adding a maximum daily token limit policy:
- id: "daily_user_token_limit"
name: "Enforce daily token budget per user"
type: "token_limit"
channel: "whatsapp"
message_type: "marketing"
is_enabled: true
rules:
max_tokens: 1000Implement the Evaluation Logic
In pkg/policy/policy.go, implement a handler for the new policy type in EvaluatePolicies:
case "token_limit":
// Parse rules: { "max_tokens": 1000 }
// Query usage stats from DB and verify against rules
// Return allowed = false if exceededBusiness 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.
2. Registering Custom MCP Tools
The Model Context Protocol Server exposes tools via standard input/output. All tools are registered in pkg/mcp/server.go.
To add a new tool (e.g., get_customer_profile):
Register the Tool Schema
In registerTools():
s.mcpServer.AddTool(mcp.NewTool("get_customer_profile",
mcp.WithDescription("Retrieve customer profiles and metadata tags"),
mcp.WithString("customer_id", mcp.Required(), mcp.Description("Recipient phone number")),
), s.handleGetCustomerProfile)Implement the Tool Handler
Create a handler function in pkg/mcp/server.go:
func (s *Server) handleGetCustomerProfile(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
customerID, err := req.RequireString("customer_id")
if err != nil {
return mcp.NewToolResultError("missing customer_id"), nil
}
profile, err := s.userManager.GetOrCreateCustomer(ctx, customerID, "whatsapp")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
resJSON, _ := json.Marshal(profile)
return mcp.NewToolResultText(string(resJSON)), nil
}3. Extending Message Queues (NATS)
The system uses NATS JetStream streams to organize asynchronous worker tasks.
To add a new queue (e.g. META_MCP_ANALYTICS for asynchronous analytics streaming):
Declare the Stream
In pkg/delivery/orchestrator.go:
_, err = o.js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{
Name: "META_MCP_ANALYTICS",
Subjects: []string{"analytics.*"},
Retention: jetstream.WorkQueuePolicy,
})Add Publisher Method
To Orchestrator:
func (o *Orchestrator) PublishAnalytics(ctx context.Context, event string, data []byte) error {
_, err := o.js.Publish(ctx, "analytics."+event, data)
return err
}Write a Worker Consumer
Similar to Worker in pkg/delivery/worker.go, create a new worker file under pkg/delivery that creates a consumer for the META_MCP_ANALYTICS stream and consumes its messages in a background loop.
4. Running Tests
# 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 |
|---|---|
pkg/compliance | 93.9% |
pkg/errorintel | 100.0% |
pkg/config | 96.2% |
pkg/observability | 100.0% |
pkg/ratelimit | 87.5% |
pkg/webhook | 83.6% |
pkg/state | 83.3% |
pkg/userintel | 82.1% |
pkg/policy | 79.5% |
pkg/template | 78.9% |
pkg/campaign | 77.1% |
pkg/delivery | 73.8% |
pkg/mcp | 61.6% |
Benchmark Result
| Tool | Latency | vs. Target |
|---|---|---|
check_compliance() | 1.69 ms | ~30× faster than 50ms target |
5. Contributing
- Fork the repository.
- Create a feature branch:
git checkout -b feature/my-change - Run tests before submitting:
go test -count=1 -p 1 ./... - Submit a pull request with a clear description of the change.