TL;DR
Model Context Protocol (MCP) has become the de-facto standard for connecting LLMs to enterprise tools and data. But most public examples are toys: a Python "hello world" with no authentication, no row-level security, no tests. In this article we publish numoru-ia/mcp-templates-es, ten production-ready MCP servers: CRM (HubSpot/Pipedrive), WhatsApp Business Cloud, Mexican CFDI 4.0 invoicing, Google Calendar, Postgres with multi-tenant RLS, Qdrant RAG, tickets (Zendesk/Freshdesk), inventory, payments (Stripe/Mercado Pago) and documents (Google Drive). All in Go and TypeScript, with OAuth 2.1, e2e tests, Docker and optional Cloudflare Workers deployment.
Why "MCP templates" are needed
The MCP spec solves transport (stdio, HTTP with SSE, streamable HTTP) and response shape (resource, tool, prompt). It leaves three critical decisions unguided:
- Authentication and authorization. How does the server verify that user X can read their company's contacts but not another's?
- Idempotency and safe writes. What happens when the LLM calls
create_invoicetwice because of a timeout? How do you avoid duplicates? - Typed contracts with predictable errors. The LLM needs consistent responses; if your tool sometimes returns
nulland sometimes{error}, the agent breaks.
The templates in this repo solve the three points uniformly. Every server follows the same structure:
mcp-<name>/
├── cmd/server/main.go # entrypoint (or src/index.ts for TS)
├── internal/
│ ├── auth/ # OAuth 2.1 + tenant resolution
│ ├── tools/ # exposed tools
│ ├── resources/ # exposed resources
│ ├── prompts/ # parameterized prompts
│ └── storage/ # persistence
├── migrations/ # if it uses its own DB
├── tests/e2e/ # real MCP client + assertions
├── Dockerfile
├── wrangler.toml # optional: Cloudflare Workers
└── README.md
The standard resource/tool/prompt pattern
Every template exposes the three MCP types with strict rules:
Resources
Readable data, identified by URI. Always valid, versioned JSON.
// Example: CRM contacts resource
// URI: crm://contacts/{contact_id}
type ContactResource struct {
ID string `json:"id"`
TenantID string `json:"tenant_id"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
// ...
}
Tools
Actions with side effects. Each tool takes a unique operation_id used as idempotency key.
// create_invoice(customer_id, items, operation_id) → invoice_id
// If an invoice with that operation_id exists, it returns it; never duplicates.
Prompts
Reusable templates the LLM client can invoke by name.
"create_follow_up_email(contact_id, tone='friendly')"
→ returns formatted messages ready for Claude/GPT
The 10 published templates
1. mcp-crm
Connects HubSpot or Pipedrive. Resources: contacts, deals, companies. Tools: create_contact, update_deal_stage, log_activity. OAuth 2.1 authentication with refresh token encrypted in Postgres. Multi-tenant: each token is bound to a workspace_id, and every tool filters by it before calling upstream.
func (s *Server) createContact(ctx context.Context, args CreateContactArgs) (*Contact, error) {
tenantID, err := auth.TenantFromContext(ctx)
if err != nil {
return nil, mcp.ErrUnauthorized
}
return s.hubspot.CreateContact(ctx, tenantID, args)
}
2. mcp-whatsapp
Wrapper for WhatsApp Business Cloud API. Resources: conversations, messages. Tools: send_text, send_template, send_media, mark_as_read. Includes a mandatory guardrail: it forbids sending messages outside the 24h window without an approved template (prevents the LLM from violating Meta's policy).
3. mcp-cfdi
Electronic invoicing for Mexico 4.0. Tools: create_invoice, cancel_invoice, get_xml, get_pdf. Integrates with PAC (Facturama, Finkok, SW Sapien) via an interchangeable driver. Validates RFC, tax regime and CFDI use before stamping. Stores the stamped XML in Spaces and returns a signed URL.
4. mcp-calendar
Google Calendar + Microsoft Graph. Resources: events, availability. Tools: create_event, find_slot, cancel. Includes a find_slot algorithm that respects the user's timezone, configurable working hours and existing events — the agent doesn't need to implement availability logic.
5. mcp-postgres-rls
Most critical for multi-tenant SaaS. Exposes Postgres as MCP with real row-level security enabled at the database level. The server sets SET app.current_tenant = $1 on every connection in the pool, and RLS policies ensure that an LLM-injected query cannot read rows from another tenant.
CREATE POLICY tenant_isolation ON contacts
USING (tenant_id::text = current_setting('app.current_tenant'));
Tools: query (SELECT validated by parser), execute (only INSERT/UPDATE/DELETE with a table allowlist), describe_schema.
6. mcp-qdrant-rag
Retrieval Augmented Generation as an MCP service. Resources: collections, documents. Tools: search_semantic, search_hybrid (dense + BM25), add_document, reindex. Supports reranking with local BGE-reranker v2-m3 and Anthropic's Contextual Retrieval. Optional Langfuse traces.
7. mcp-tickets
Zendesk and Freshdesk. Resources: tickets, agents. Tools: create_ticket, assign, reply, close, merge. Includes automatic priority ranking using a local small model via LiteLLM.
8. mcp-inventory
Generic for catalogs: products, stock, locations. Tools: search_product, check_stock, reserve, release. Adapter-based driver: Shopify, WooCommerce, Odoo or your own database.
9. mcp-payments
Stripe + Mercado Pago. Tools: create_payment_link, refund, get_transaction, list_disputes. Does not expose direct create_charge with card data — forces the LLM to use hosted pages or tokens, mitigating PCI risk.
10. mcp-drive
Google Drive + Box. Resources: files, folders. Tools: search, download, upload, share. Includes automatic ingestion with Unstructured.io + chunking with Chonkie so content becomes indexable by mcp-qdrant-rag.
Standardized OAuth 2.1
All templates share the same OAuth flow. The MCP client sends an opaque token; the server validates against Postgres and resolves the tenant. Tokens are refreshed with a 5-minute margin before expiry.
type Principal struct {
UserID string
TenantID string
Scopes []string
}
func (s *Server) middleware(next mcp.Handler) mcp.Handler {
return mcp.HandlerFunc(func(ctx context.Context, req mcp.Request) (mcp.Response, error) {
token := mcp.AuthTokenFromContext(ctx)
principal, err := s.auth.Validate(ctx, token)
if err != nil {
return nil, mcp.Unauthorized("invalid token")
}
ctx = auth.WithPrincipal(ctx, principal)
return next.Handle(ctx, req)
})
}
Idempotency: the key everyone forgets
Every tool with side effects accepts an operation_id parameter. The server keeps a Postgres table operations(operation_id, tenant_id, tool, result_json, created_at) with a compound unique index. If the same operation arrives twice, the cached result is returned without calling upstream again.
This resolves three classic LLM agent bugs:
- Client retry after timeout → invoice duplicate
- Agent deciding "let me try again just in case" → email duplicate
- Multi-step flow interrupted halfway → partial operation repeated
Deployment: three options
Option A — Local Docker Compose
docker compose up -d brings up any template with its Postgres, Redis and HTTP server. Ideal for development and self-host clients.
Option B — Cloudflare Workers (serverless MCP)
Every TS template includes wrangler.toml. Deploy in one command:
npx wrangler deploy
Cloudflare Workers supports MCP over streamable-http natively since late 2025. The server handles bursts without paying for idle time — perfect for SMB clients receiving 200 requests/day.
Option C — Shared Digital Ocean droplet
Using the stack from Self-hosted AI stack on a DO droplet, the 10 MCP servers mount behind Nginx as sub-paths (/mcp/crm, /mcp/whatsapp, ...). A single shared Postgres with separate schemas.
Standardized e2e testing
Each template includes a suite that brings the server up in an ephemeral container and runs a real MCP client against it. No mocks — assertions validate the full flow of OAuth, idempotency and typed errors.
func TestCreateInvoiceIdempotent(t *testing.T) {
srv := testutil.StartServer(t)
client := mcp.Dial(srv.URL, testToken)
args := CreateInvoiceArgs{OperationID: "op-123", /* ... */}
r1, _ := client.CallTool(ctx, "create_invoice", args)
r2, _ := client.CallTool(ctx, "create_invoice", args)
assert.Equal(t, r1.InvoiceID, r2.InvoiceID, "same operation_id must return the same invoice")
}
Integration with Claude Agent SDK
Minimal example: an agent that uses three of our MCP servers to schedule a commercial demo from a WhatsApp conversation.
from anthropic import Anthropic
from mcp import stdio_client
client = Anthropic()
servers = [
stdio_client("./mcp-whatsapp"),
stdio_client("./mcp-crm"),
stdio_client("./mcp-calendar"),
]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
tools=await aggregate_tools(servers),
messages=[{
"role": "user",
"content": "A new lead messaged via WhatsApp asking for a demo. Create a contact in CRM and book next Tuesday 3pm."
}],
)
The agent orchestrates the three MCPs without any ad-hoc glue code.
Compatibility with other MCP clients
Tested and working with:
- Claude Desktop
- Claude Code CLI
- Cursor
- Continue.dev
- Windsurf
- OpenAI Agents SDK (via shim)
- VS Code MCP extension
Business & commercial impact
Why templates compress deal cycles
An enterprise chatbot integrated with CRM + WhatsApp + calendar used to be a 3-month build. With templates the delivery timeline shrinks to 4-6 weeks because 80% of the integration code is already written, tested and deployed. That changes the sales conversation: instead of "give us 90 days," you quote "live agent in 6 weeks, fixed price." Buyers close faster at a higher attached margin.
Observed delivery time for a 5-tool MCP-enabled B2B chatbot: CRM + WhatsApp + calendar + payments + CFDI. From kickoff to production deployment.
- From scratch
- With Numoru templates
Numoru engagement telemetry, 2024-2026 internal data.
Industries and ticket ranges
Chatbot build on top of templates — ticket by vertical (USD)
Public benchmarks supporting the pitch
Anthropic — Model Context Protocol launch
Meta — WhatsApp Business Platform adoption
Illustrative case — LATAM agency reselling templates
Boutique AI agency (Mexico / Buenos Aires) using templates for 8 enterprise bot builds
ROI calculator — enterprise buyer of an integrated chatbot
Mid-market retailer replacing Tier-1 customer support (12 months)
| Implementation (one-time) | −$32,000 |
| Ops retainer (12 mo × $1,200) | −$14,400 |
| Bot variable cost (104k tickets × $0.22) | −$22,880 |
| Support labour avoided (104k × $4.80) | +$499,200 |
| WhatsApp conversion lift | +$180,000 |
| CFDI automation (time saved) | +$42,000 |
| Net year-1 contribution | +$651,920 |
Pricing tiers Numoru sells
- All 10 production servers
- Go + TS reference implementations
- OAuth 2.1 + RLS + idempotency
- Tests + Docker + Workers config
- Community support (GitHub issues)
- 3-6 tool integrations
- Claude Agent SDK orchestration
- WhatsApp / web / Slack channel
- Langfuse observability
- 4-8 week delivery
- 60-day warranty + handover
- Unlimited end-client projects
- Private fork + logo swap
- Priority bug-fix SLA
- Quarterly template updates
- 8% rev-share on delivered builds
- Co-marketing option
Ops retainer after a build: $900-2,400 / mo depending on scope and SLA.
FAQ
Can I use these templates commercially?Yes, Apache 2.0 license. Fork, modify, charge.
How expensive is it to maintain?Base stack (droplet + Postgres + Redis) is ~$50/month. The templates add negligible CPU/RAM because most work is I/O against upstream APIs.
What if upstream (HubSpot, Stripe, etc.) changes its API?Each template has an isolated internal/driver/<vendor>/ directory. The MCP contract is stable; vendor changes only touch the driver.
Can they coexist with each provider's official MCPs?Yes. These templates exist because the official ones are few, immature or don't cover idempotency + multi-tenancy. When the official ones catch up, migration is trivial.
Security tests?CI runs Semgrep (p/owasp-top-ten), Bearer (PII detection) and Trivy (CVEs in Docker image) on every PR.
Next steps
The repo github.com/numoru-ia/mcp-templates-es is published with the 10 servers, executable documentation and an examples/ folder with reference agents. The 2026 plan adds 5 more templates: ERP (Odoo/NetSuite), e-commerce (Shopify/VTEX), HR (BambooHR), digital signatures (Mifiel/DocuSign) and taxes (SAT/AFIP).
If your SMB uses ChatGPT Enterprise, Claude for Work, or any commercial agent, and you want to connect it to your operation without 6 months of custom integration, these templates are the shortest path we know.