wafle MCP server
Provides tools for exporting Google Ads and accessing analytics by period, as well as checking Google connection status.
Provides tools and prompts to connect Meta to a store, sync product catalog to Commerce Manager, export Meta audiences, and check Meta connection status.
Provides resource to check TikTok connection status in the ads connections.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@wafle MCP server show me orders placed today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@wafle/mcp — Model Context Protocol server for wafle
The first MCP server for the wafle commerce platform. Lets Claude Desktop, Claude Code, agents, and any MCP-compatible client drive a wafle tenant — stores, products, orders, pricing, gateways, audiences, system — by talking to it.
What this is
Wafle is the LLM-first multi-tenant commerce platform. Its REST API at https://wafle.click/wp-json/waffle/v1/ does the work; this MCP server exposes that work as 68 tools, 14 resources, and 5 server-defined prompts an LLM can pick from. Every wafle feature should land here as a tool first, UI second.
This is a thin, well-typed wrapper. No business logic lives in this package — bugs in pricing or order flow belong to the wafle backend.
Related MCP server: negotiate-mcp
Install
git clone <repo>
cd wafle-mcp
npm install
npm run buildConfigure
Set environment variables (or copy .env.example to .env):
WAFLE_API_URL=https://wafle.click/wp-json/waffle/v1 # default
WAFLE_API_KEY=<your wafle admin key> # required (upstream)
WAFLE_TIMEOUT_MS=30000 # optional
# Only used by --transport=http:
WAFLE_MCP_HTTP_HOST=0.0.0.0
WAFLE_MCP_HTTP_PORT=7100
# Tenant-scoped JWT auth (recommended). Same value as WAFFLE_MCP_JWT_SECRET
# in the backend mu-plugin. Generate: openssl rand -hex 64
WAFLE_MCP_JWT_SECRET=<shared HS256 secret>
WAFLE_MCP_REQUIRE_JWT=1 # refuses legacy bearers in prod
# Legacy admin-tier bearers (cross-tenant). Used as fallback when REQUIRE_JWT is unset.
WAFLE_MCP_TOKENS=<comma-separated bearer tokens>
LOG_LEVEL=infoWAFLE_API_KEY is the upstream wafle key the MCP server uses to talk to the backend (master, scoped at the backend layer). Tenant isolation for the MCP itself is enforced by WAFLE_MCP_JWT_SECRET — the backend mints HS256 JWTs carrying tenant_id + tenant_slug + scope, and this server filters tools/list and rewrites every per-store call to the JWT's tenant. See src/auth/jwt.ts, src/auth/tenant.ts.
Tenant tokens
Clients obtain a tenant-scoped JWT from the wafle backend:
POST /wp-json/waffle/v1/admin/account/mcp/issue-token
X-Wafle-Admin-Key: <store key for that tenant>
{ "ttl_days": 30 }Response includes { token, jti, tenant_slug, expires_at, mcp_url }. The client then sends Authorization: Bearer <token> to mcp.wafle.click/mcp. With this token:
tools/listonly shows the tenant's tools — admin-only tools (wafle_system_*,wafle_gateways_*,wafle_stores_list/create,wafle_auth_keys_*) are filtered out server-side.Every per-tenant tool ignores the
slugargument and uses the JWT'stenant_sluginstead. A token for tenant A cannot read or mutate tenant B regardless of arguments passed.Tokens can be revoked via
POST /admin/account/mcp/revoke-token({ jti }) and listed viaGET /admin/account/mcp/tokens.
Run
stdio (Claude Desktop, Claude Code local)
node dist/index.js --transport=stdioLogs go to stderr. Stdout is reserved for the JSON-RPC framing — never console.log from a tool handler.
HTTP / Streamable HTTP (remote agents, web)
node dist/index.js --transport=httpListens on WAFLE_MCP_HTTP_PORT (default 7100). Single endpoint at POST /mcp per the MCP Streamable HTTP spec (2025-03-26). GET /healthz for liveness.
Bearer auth on every request: Authorization: Bearer <token> where <token> is one of the values in WAFLE_MCP_TOKENS. The MCP server refuses all traffic if no tokens are configured.
Connect Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"wafle": {
"command": "node",
"args": ["/absolute/path/to/wafle-mcp/dist/index.js", "--transport=stdio"],
"env": {
"WAFLE_API_KEY": "your-wafle-admin-key",
"WAFLE_API_URL": "https://wafle.click/wp-json/waffle/v1",
"LOG_LEVEL": "info"
}
}
}
}Restart Claude Desktop. You should see "wafle" with 63 tools in the /mcp panel.
There is also an example at examples/claude-desktop-config.json.
Connect Claude Code
Project-scoped: drop a file at <repo>/.mcp.json:
{
"mcpServers": {
"wafle": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/wafle-mcp/dist/index.js", "--transport=stdio"],
"env": { "WAFLE_API_KEY": "your-key" }
}
}
}User-scoped: append to ~/.claude/.mcp.json (same shape).
For the deployed HTTP transport at mcp.wafle.click:
{
"mcpServers": {
"wafle": {
"type": "http",
"url": "https://mcp.wafle.click/mcp",
"headers": { "Authorization": "Bearer <bearer token>" }
}
}
}Tool catalogue (68)
Domain | Tools |
auth |
|
stores |
|
products |
|
pricing |
|
orders |
|
customers |
|
gateways |
|
shipping |
|
coupons |
|
abandoned |
|
analytics |
|
exports |
|
pixels |
|
system |
|
meta |
|
Every tool has a markdown description with usage guidance, a Zod schema with .describe()-annotated fields, scope requirements, and readOnlyHint/destructiveHint/idempotentHint annotations to help the LLM pick wisely.
The long-running tools (_sync_trigger_and_wait, _csv_import, _ads_sync_full) emit notifications/progress while polling — clients that support progress (Claude Desktop) show a live progress bar.
Resources (14)
MCP Resources expose read-only context the LLM can pull in without spending a tool call. Reference them with @<uri> in Claude Desktop or by URI in any client.
URI | TTL | Purpose |
| 30s | Backend health snapshot. |
| 1h | Catalog of every API scope (domain, tier, label). |
| 1h | REST canonical shapes. |
| 1h | Architecture overview. |
| 60s | Lean list of every store. |
| 60s | Full store snapshot (settings + 7d KPIs + abandoned + last order). |
| 30s | Last 20 orders with summary fields. |
| 60s | Top 20 abandoned carts. |
| 5min | 7-day analytics. |
| 5min | 30-day analytics. |
| 2min | Top 20 products. |
| 60s | Customer segments. |
| 60s | Last 10 campaigns. |
| 5min | Meta/Google/TikTok connection status. |
Cache is in-memory per session, with TTL per resource. Manual invalidation: wafle_resources_invalidate { uri_pattern }. Long-running tools auto-invalidate the affected store.
See docs/RESOURCES.md for full details and examples.
Prompts (5)
Server-defined parametric workflows for the most common BATTO operations. The client surfaces a picker; pick → fill args → conversation starts with a fully-rendered plan.
Name | Use case |
| End-to-end onboarding (store + MP + catalog + frontend API key). |
| Mark order shipped with tracking + customer email. |
| Build segment + create email campaign (immediate or scheduled). |
| Connect Meta to a store + sync catalog to Commerce Manager. |
| Diagnose failed payment + optionally retry via secondary gateway. |
See docs/PROMPTS.md for argument schemas and example invocations.
Conversational examples
See examples/prompts/:
01-onboarding-tienda-nueva.md — onboarding a new client end to end.
02-pedido-enviar.md — single-shot logistics action.
03-segmentar-y-campania.md — segment + campaign.
04-conectar-meta-y-sync.md — connect Meta + catalog sync.
05-debug-orden-fallida.md — payment failure diagnosis.
The 5 prompts above are converted to server-defined MCP prompts in src/prompts/.
Scopes
Each tool declares a scope (e.g. orders:write, gateways:admin). At startup the server calls wafle_auth_me to retrieve the granted scopes; if wafle's /auth/me returns type=master we grant ALL_SCOPES. If it returns neither scopes nor a known type, the server runs in warn-mode — scope checks are skipped and a startup warning is logged.
The full matrix lives in src/auth/scopes.ts.
Architecture
See ARCHITECTURE.md. TL;DR: thin TypeScript wrapper over wafle REST, Fastify for HTTP, the official @modelcontextprotocol/sdk, Zod for validation, pino for logs (stderr only — required for stdio).
Deploy
docker compose up -dor with the systemd unit at deploy/systemd/wafle-mcp.service. The repo includes Dockerfile (multistage, alpine runtime) and a sample nginx config for mcp.wafle.click.
Troubleshooting
401 waffle_unauthorized:WAFLE_API_KEYis missing or wrong. Get the master key from the waffle container at/root/.waffle-creds.txt.Claude Desktop says no tools: confirm the path in
claude_desktop_config.jsonis absolute anddist/index.jsexists. Runnode dist/index.js --transport=stdioin a terminal — if it doesn't start, fix the env first.Stdout corruption: don't
console.loganywhere. All logs must go viagetLogger()(which writes to stderr).HTTP transport refuses traffic: set
WAFLE_MCP_TOKENSand passAuthorization: Bearer <token>.Wafle says
forbidden, invalid master key: some endpoints (e.g./system/versions) check a different key. Verify withcurl -H "X-Wafle-Admin-Key: $KEY" https://wafle.click/wp-json/waffle/v1/auth/mefirst.
Development
npm run dev # tsx-watch, stdio
npm run dev:http # tsx-watch, http
npm test # vitest
npm run test:coverage
npm run lint
npm run typecheckLicense
MIT — see LICENSE.
Available Tools
124 toolswafle_abandoned_listARead-onlyIdempotent
List abandoned cart sessions: last activity, items, optional email captured before exit.
Use to estimate recovery potential or to feed a manual outreach campaign.
Inputs: slug (required), page, per_page, since_ts, +1 more.
wafle_abandoned_send_recoveryAIdempotent
Trigger a recovery email to the captured address of an abandoned-cart session. The email contains a one-click recovery link with the cart pre-filled.
Idempotent: re-sending within the cooldown window is a no-op (wafle returns the existing send id).
Inputs: slug (required), session_id (required), template, coupon_code.
wafle_ads_anomalies_listARead-onlyIdempotent
List ads anomalies detected by the cron-driven detector (runs every 30 minutes). Each anomaly includes kind (cpa_spike, roas_break, conversion_drop, spend_overrun, learning_limited_stuck, tracking_drift), severity, scope, and the metrics that triggered it.
Anomalies fire admin-inbox notifications (warning+) and push notifications (critical only) with a 6h cooldown per (kind, scope_id) pair. Use this tool to read raw history.
Inputs: slug (required), kind, page, since, +3 more.
wafle_ads_audience_overlap_checkARead-onlyIdempotent
Compute % overlap between custom audiences in the connected ad account. Returns a matrix (audience_a × audience_b → overlap_pct + overlap_users). Use this when the merchant runs many similar adsets — high overlap (>40%) typically means they're bidding against themselves and inflating CPM. Pass specific audience_ids to limit the matrix or omit to compare all audiences with > min_size users.
Note: Meta's overlap API is sampled (it builds the matrix once a day), so values may be a few hours stale. The wafle backend caches results for 6 hours per (slug, audience_set) tuple.
Inputs: slug (required), min_size, audience_ids.
wafle_ads_breakdown_by_creativeARead-onlyIdempotent
Per-creative performance breakdown for a campaign (or whole account if campaign_id omitted). Returns spend, impressions, clicks, conversions, ROAS and CPA for every creative_id active in the window. Cross-tabbed against wafle CAPI orders, so ROAS reflects server-side truth, not Meta's pixel.
Use when you need to find the one creative carrying a campaign vs the ones bleeding spend. Sort defaults to spend desc; a winner flag tags creatives whose ROAS is in the top quartile AND spend is above the per-creative significance floor (default 5,000 cents).
Inputs: slug (required), sort, range, campaign_id, +1 more.
wafle_ads_bulk_pauseADestructiveIdempotent
Pause many Meta campaigns in a single tool call. Returns per-id success/failure so partial successes are visible.
Best for ROAS-floor sweeps ("pause everything below 1.5x last 7d") and seasonal cleanup. The wafle backend serializes the underlying Marketing API requests with a 1 RPS throttle to stay below Meta's per-app rate limit.
Inputs: slug (required), campaign_ids (required).
wafle_ads_campaign_pauseADestructiveIdempotent
Pause a Meta Ads campaign by id. Idempotent — pausing an already-paused campaign returns ok=true. Uses the tenant's connected Meta access token; the LLM does not need to pass credentials.
Use when ROAS is below threshold or as the apply step of a pause-recommendation. For multi-campaign pauses, prefer wafle_ads_bulk_pause to avoid round-trip cost.
Inputs: slug (required), campaign_id (required).
wafle_ads_campaign_resumeAIdempotent
Resume a paused Meta Ads campaign by id. Sets status to ACTIVE. Idempotent for already-active campaigns.
Note: campaigns paused for 14+ days lose their Learning Phase signal — Meta will re-enter Learning when you resume them.
Inputs: slug (required), campaign_id (required).
wafle_ads_campaign_update_budgetADestructive
Update a Meta campaign's budget. Pass daily_budget_cents (preferred) or lifetime_budget_cents — the two are mutually exclusive in the Marketing API.
Cents are in the ad account currency. The recommender follows a +30% / max +50% rule when scaling winners; if you call this directly, mirror that constraint to avoid blowing the Learning Phase.
Inputs: slug (required), campaign_id (required), daily_budget_cents, lifetime_budget_cents.
wafle_ads_compare_periodsARead-onlyIdempotent
Compare two date ranges (e.g. '2026-04' vs '2026-03', or two arbitrary date windows) and return delta % per metric: spend, revenue, ROAS, CPA, conversions, profit. Both ranges are evaluated against the wafle CAPI server-side truth so the comparison is honest (Meta's pixel attribution can drift quarter to quarter and produce false deltas).
Use to answer 'how did April do vs March?' or 'did the new creative pack improve things in the last 14 days vs the prior 14?'. Ranges can be passed as ISO months or as start/end dates; the two windows must NOT overlap.
Inputs: slug (required), period_a (required), period_b (required).
wafle_ads_creative_performance_logARead-onlyIdempotent
Daily timeseries for a single creative_id since since. Each row: spend, impressions, clicks, conversions, revenue, roas, frequency, ctr, cpm.
Use to detect (a) Learning Phase exit, (b) creative fatigue (frequency rising + CTR falling), (c) the right scale moment (3+ days of stable ROAS above target). The response also includes fatigue_score (0..1, higher = more fatigued) and phase ∈ {learning, active, fatigued, off}.
Inputs: slug (required), since (required), creative_id (required), until.
wafle_ads_generate_report_monthlyARead-onlyIdempotent
Generate a structured monthly ads report for a store. Returns total spend, total revenue, profit, blended ROAS, top 5 winning campaigns, bottom 5 losing campaigns, and a recommendations array of human-readable strings. Designed as the input for Claude to author the executive narrative — DO NOT paste raw JSON into the report; rewrite into prose using recommendations as bullet points and the winners/losers as supporting evidence.
Backed by /stores/:slug/marketing/profit?range=... (which already aggregates spend × wafle revenue per campaign) plus a month-aware aggregation layer.
Inputs: slug (required), month (required).
wafle_ads_performance_summaryARead-onlyIdempotent
Account-level cross-tabbed performance — joins Meta Marketing API spend/impressions/clicks with wafle CAPI orders/revenue.
Each campaign returns: spend, meta_reported_orders (from pixel), wafle_orders (server-side truth), cpa_real_cents (spend / wafle_orders), roas_real, learning_phase, plus a prev_period block for trend analysis. Use this as the input to any optimization decision — it's what the recommender feeds the LLM.
Inputs: slug (required), days.
wafle_ads_propose_pause_underperformersARead-onlyIdempotent
READ-ONLY proposer: returns a list of adsets with ROAS below threshold_roas AND spend above min_spend_cents over range. Each item carries a recommendation ∈ {pause, reduce_budget, keep} based on (a) how far below threshold, (b) Learning Phase status, (c) trend vs previous period.
This tool NEVER mutates. To execute, the caller must explicitly call wafle_ads_campaign_pause, wafle_ads_bulk_pause, or wafle_ads_campaign_update_budget with the ids returned here. The output is shaped to be pasted back into a follow-up tool call by the LLM.
Inputs: slug (required), range, campaign_id, threshold_roas, +1 more.
wafle_ads_recommendation_applyADestructiveIdempotent
Apply a wafle ads recommendation by id — runs the underlying writer action (pause campaign, raise budget, etc.) and marks the recommendation applied. Idempotent: re-applying returns the previous result.
If the action requires human judgment (request_human_review, generate_creative_variants), the call queues the work and returns ok=true with queued: true.
Inputs: slug (required), recommendation_id (required).
wafle_ads_recommendations_listARead-onlyIdempotent
List ads recommendations generated by wafle's AI engine. Recommendations cross-tab the Meta API spend with the server-side truth (wafle CAPI orders + revenue), so CPA/ROAS reflect what actually happened — not Meta's own attribution.
Each card has: title, description, action (the actual writer call to apply it), confidence (0..1), expected_impact, severity. Apply with wafle_ads_recommendation_apply.
Inputs: slug (required), page, status, per_page, +1 more.
wafle_ads_sync_fullA
Run a full ads-platform catalog sync (Meta Catalog API or equivalent) AND wait until it finishes. Emits progress notifications.
Long-running (5+ minutes for large catalogs). For fire-and-forget, call the underlying create endpoint directly.
Inputs: connection_id (required), filters, timeout_seconds.
wafle_agents_activateA
Activate an agent — moves status to active, which makes it eligible for scheduled/event triggers. No-op if already active.
Inputs: slug (required), agent_slug (required).
wafle_agents_createA
Create a new custom agent. Two paths:
from_template— clone one of the 5 pre-armed templates (customer-support-bot, content-writer-nightly, stock-watcher, abandoned-recovery, fraud-detector). Overrideslug/nameif needed.From scratch — supply
name,system_prompt,tools_allowed,guardrails,trigger_type(+ trigger_config). Usewafle_agents_tool_catalogfirst to see what tools exist.
Cost guardrail (max_cost_per_run_cents) is hard-capped at 5000 (USD 50). Max turns is hard-capped at 50.
Inputs: slug (required), name, model, max_turns, +9 more.
wafle_agents_getARead-onlyIdempotent
Get one agent by its slug — full definition including system_prompt, tools_allowed, guardrails, trigger_config and stats counters.
Inputs: slug (required), agent_slug (required).
wafle_agents_listARead-onlyIdempotent
List custom agents defined for a store. Each agent has system_prompt + tools whitelist + guardrails + trigger. Filter by status (draft/active/paused/archived) or trigger_type.
Inputs: slug (required), status, trigger_type.
wafle_agents_pauseA
Pause an active agent. Triggers stop firing; existing runs unaffected.
Inputs: slug (required), agent_slug (required).
wafle_agents_runA
Manually dispatch a run for an agent. Returns the run_id and the synchronous run row (ends in status=done|failed|awaiting_approval). Use wafle_agents_runs_get to poll.
Inputs: slug (required), input (required), agent_slug (required), context.
wafle_agents_runs_approveADestructive
Approve a run that is awaiting_approval. Resumes execution from the pending tool call. Optional note saved to the audit log.
Inputs: slug (required), run_id (required), note.
wafle_agents_runs_getARead-only
Get a specific run with its full conversation + audit log (steps: user_input, assistant_text, tool_call, tool_result, approval_request, approval_granted, error).
Inputs: slug (required), run_id (required).
wafle_agents_runs_listARead-only
List runs for an agent — paginated, filterable by status. Each row: status, tokens, cost_cents, duration_ms.
Inputs: slug (required), agent_slug (required), page, status, +1 more.
wafle_agents_runs_rejectA
Reject a run that is awaiting_approval. Run goes to cancelled; the pending tool call is NOT executed.
Inputs: slug (required), run_id (required), note.
wafle_agents_statsARead-onlyIdempotent
Aggregated stats for an agent: total runs, success rate, total cost, top tool names called.
Inputs: slug (required), agent_slug (required).
wafle_agents_templatesARead-onlyIdempotent
List the 5 pre-armed agent templates: customer-support-bot, content-writer-nightly, stock-watcher, abandoned-recovery, fraud-detector. Use the id field as from_template in wafle_agents_create.
Inputs: no named parameters.
wafle_agents_tool_catalogARead-onlyIdempotent
List the catalog of tools that can be added to an agent's tools_allowed. Each entry: name, description, scope required, destructive flag, JSON Schema for input.
Inputs: no named parameters.
wafle_agents_updateA
Patch an existing agent — change system_prompt, tools_allowed, guardrails, trigger_config, model, status, etc. Slug + tenant_id are immutable.
Inputs: slug (required), patch (required), agent_slug (required).
wafle_ai_categorizeA
Auto-classify products without a category. Call with a list of SKUs and a list of allowed categories. Each product gets { category, confidence } (or null if nothing fits). Accept the job to write category overrides into the catalog.
Inputs: slug (required), product_skus (required), available_categories (required).
wafle_ai_jobs_acceptA
Apply an AI job's output to the platform.
product_description → writes data.descriptions. on the catalog row.
categorize → writes data.category overrides on each product row.
review_summary → caches summary on the reviews aggregates row. Other types have no platform side effect (translation already cached, segment_compile is read-only).
Inputs: id (required), slug (required).
wafle_ai_jobs_editA
Save user edits on an AI job's output and apply them. For product_description, the edited text is what gets written to data.descriptions..
Inputs: id (required), slug (required), user_edits (required).
wafle_ai_jobs_getARead-onlyIdempotent
Fetch a single AI job by id. Includes input_payload, output_payload, tokens, cost, model, duration, and user review status.
Inputs: id (required), slug (required).
wafle_ai_jobs_listARead-onlyIdempotent
Paginated list of AI jobs for a store. Filter by job_type, status, or user_review. Use to surface a 'pending review' queue or to find a specific recent job.
Inputs: slug (required), page, status, job_type, +2 more.
wafle_ai_jobs_rejectA
Mark an AI job's output as rejected. Use to keep usage stats clean and to preserve learning signal for prompt tuning.
Inputs: id (required), slug (required), reason.
wafle_ai_product_describeA
Generate a sales copy description for a product. Reads name + attributes + images from the catalog, runs the configured LLM, and stores the output as a 'pending review' job. Call wafle_ai_jobs_accept to apply it (writes data.descriptions. on the catalog row).
Tone: 'persuasivo' | 'tecnico' | 'breve'. Length is approximate words (±15%).
Inputs: sku (required), slug (required), tone, locale, +1 more.
wafle_ai_review_summaryA
Summarize the approved reviews of a product into 2–3 sentences plus sentiment + key points. Output goes into a job; call wafle_ai_jobs_accept to cache the summary on the reviews aggregate row (24h TTL).
Inputs: sku (required), slug (required), max_reviews.
wafle_ai_segment_compileA
Compile a natural-language description (e.g. 'clientes que compraron al menos 2 veces y abandonaron carro últimos 30 días') into the email-marketing segmentation DSL. Returns { dsl_json, validated, errors }. Pass dsl_json straight into a new segment.
Inputs: slug (required), natural_language (required).
wafle_ai_support_hintA
Customer-service co-pilot: classify an inbound message, gauge sentiment, decide if it needs escalation, and draft a friendly response. PII (emails, phones) in the message is redacted before being sent to the LLM.
Inputs: slug (required), inbound_message (required), total_orders, customer_email, +1 more.
wafle_ai_translateAIdempotent
Translate a piece of text from one language to another. Cached by sha256(source_text|source_lang|target_lang) — re-translating the same input is free.
Preserves markdown, lists, links and {{placeholders}}. Use for product descriptions, emails, or short copy snippets. Source and target are language codes ('es', 'en', 'pt', 'es-AR', 'pt-BR').
Inputs: slug (required), text (required), source_lang (required), target_lang (required).
wafle_ai_usageARead-onlyIdempotent
Token + cost aggregate for a store since a date (defaults to last 30 days). Use for the AI dashboard chart and quota guidance.
Inputs: slug (required), since.
wafle_analytics_by_periodARead-onlyIdempotent
Time-series breakdown of analytics: revenue + orders bucketed by day/week/month.
Use for charts and 'compare last 30d to previous 30d' workflows.
Inputs: slug (required), range, to_ts, bucket, +1 more.
wafle_analytics_summaryARead-onlyIdempotent
High-level KPIs for a store over a window: orders, revenue, AOV, top products, conversion funnel, abandoned-cart rate.
Use as the starting point of any 'how is store X doing?' question.
Inputs: slug (required), range, to_ts, from_ts.
wafle_auth_keys_createA
Create a new wafle API key with the given scopes. Returns the secret ONCE — store it immediately.
Use when onboarding a new dashboard user, integration, or agent. Prefer narrowly-scoped keys.
If the wafle backend has not yet implemented /auth/keys POST, this tool returns the upstream error untouched.
Admin-only: tenant clients cannot mint API keys.
Inputs: name (required), scopes (required), expires_at, store_slug.
wafle_auth_keys_listARead-onlyIdempotent
List API keys associated with the master account (or with a specific store, if the upstream key supports it).
Returns prefix + scopes for each key. Full secrets are NEVER returned by wafle. Use to audit who has access.
Admin-only: tenant clients cannot enumerate API keys.
Inputs: store_slug.
wafle_auth_meARead-onlyIdempotent
Return information about the wafle admin key currently configured for this MCP server.
Use this to verify the server is correctly authenticated before running other tools, or to debug a 401 error. The response is { ok: true, type: 'master' | 'store', store_slug?, scopes? }.
Do NOT use this to authenticate end-user requests — wafle's REST has separate magic-link auth for storefront customers.
Inputs: no named parameters.
wafle_checkout_cart_recoverARead-onlyIdempotent
List abandoned carts (cart_token has items but no paid order in wafle_orders) for a customer email hash. Used by retargeting drip flows to surface 'you left X in your cart' nudges.
Inputs: slug (required), customer_email_hash (required), since.
wafle_checkout_order_getARead-onlyIdempotent
Fetch one order from wafle_orders. order_id accepts either the numeric primary key or the public id (WK-YYYY-NNN-rand) shown on the order detail page.
Inputs: slug (required), order_id (required).
wafle_checkout_order_mark_paidAIdempotent
Manually flip a transfer/cash order to paid (proof-of-deposit verified, cash collected at delivery). Returns 422 if the order is on a webhook-driven gateway (mp / stripe) — those move via /webhooks/* automatically.
Inputs: slug (required), order_id (required), proof_ref.
wafle_checkout_order_refundADestructive
Refund a paid order — full when amount_cents is omitted/0, partial otherwise. Guardrail: any refund > 50% of total_cents requires confirm:true. The refund is recorded on the wafle_orders row; the gateway-side refund call is gateway-specific and currently records manual_refund:true in metadata (gateway API integration ships in v2).
Inputs: slug (required), order_id (required), reason, confirm, +1 more.
wafle_checkout_order_resend_emailB
Resend a transactional email tied to an order. Default template: order_confirmation. Idempotency-keyed by template+public_id+timestamp so retries don't double-send within the same minute.
Inputs: slug (required), order_id (required), template.
wafle_checkout_orders_listARead-onlyIdempotent
List orders from the wafle_orders table for a store. Returns the new checkout pipeline (cart→MP/Stripe/transfer→paid). Filterable by status, date floor (since, ISO 8601), and customer email. For legacy WC orders use wafle_orders_list (different table).
Inputs: slug (required), email, limit, since, +3 more.
wafle_coupons_createA
Create a coupon. Codes are case-insensitive. Date fields are epoch seconds (0 = no bound).
Common patterns:
type=percentage, value=10→ 10% off whole cart.type=fixed, value=5000, applies_to='product', applies_to_ids=[123]→ ARS 5000 off product 123.type=free_shipping→ no shipping cost.
Inputs: code (required), slug (required), type (required), value (required), +8 more.
wafle_coupons_deleteADestructiveIdempotent
Delete a coupon by id. Past usage history is preserved on orders.
Inputs: slug (required), coupon_id (required).
wafle_coupons_listARead-onlyIdempotent
List all coupons of a store. Each row: code, type, value, usage, validity dates, applies-to scope.
Use to audit active discounts or to find a code before editing.
Inputs: slug (required).
wafle_coupons_updateAIdempotent
Patch a coupon by id. Only sent fields change.
Inputs: slug (required), coupon_id (required), value, active, +2 more.
wafle_csv_importA
Import a CSV product feed into a store with catalog_mode=csv. Long-running. Emits progress notifications during the import (rows processed / total).
Returns the final import summary: imported, updated, errors, duration.
Inputs: slug (required), csv_url (required), mapping, timeout_seconds.
wafle_customers_getARead-onlyIdempotent
Fetch a single customer profile by email. Returns aggregated stats: lifetime value, order count, last seen, top SKUs.
Inputs: slug (required), email (required).
wafle_customers_listARead-onlyIdempotent
List customers of a store with pagination + filters: search by email/name, has-orders, segment.
Wafle treats customers as derived data over orders — there's no separate sign-up table for storefronts.
Inputs: slug (required), page, search, segment, +1 more.
wafle_customers_ordersARead-onlyIdempotent
List the orders of a single customer (by email).
Inputs: slug (required), email (required), page, per_page.
wafle_customers_segments_listARead-onlyIdempotent
List all customer segments configured for a store. Segments power the segment= filter in wafle_customers_list and the audience exports.
Inputs: slug (required).
wafle_domains_addA
Attach a new custom domain (e.g. 'mi-tienda.com') to a wafle store. Wafle generates a verification_token and returns the 3 alternative DNS instructions the tenant must apply.
After creating, the tenant updates DNS at their provider, then call wafle_domains_verify (or wait for the 5min cron) to drive verification + SSL + nginx provisioning.
Validation rules: lowercase FQDN only, no IPs, no wildcards, no .wafle.click subdomains, max 10 active domains per tenant.
Inputs: slug (required), domain (required), force_https, redirect_www, +3 more.
wafle_domains_listARead-onlyIdempotent
List the custom domains attached to a wafle store. Returns each domain's status (pending_verification / verifying / ssl_pending / active / ssl_failed / disabled), SSL expiry, verification token, and DNS-setup instructions for all 3 verification methods (TXT/CNAME/file).
Use first when the user asks 'what domains does store X have?' or before giving DNS instructions to a new tenant.
Inputs: slug (required), limit, status.
wafle_domains_statusARead-onlyIdempotent
Fetch the full status of a single attached domain — current status (pending/verifying/active/etc), SSL expiry, last renewal, log of recent events. Includes the original DNS-setup instructions so you can re-show them to the tenant.
Use to answer 'is mi-tienda.com working yet?' or to debug a stuck verification.
Inputs: id (required), slug (required), include_log.
wafle_domains_verifyAIdempotent
Trigger immediate verification + SSL + nginx provisioning for a previously-added domain. Idempotent — safe to call repeatedly. The pipeline:
Probe TXT / CNAME / file methods (any one passes).
If passed → request a Let's Encrypt cert via acme.sh.
Render the per-domain nginx config and signal a reload.
Mark the domain
activeand append events to the log.
Rate-limited to 1 attempt per minute per domain (DNS + acme upstream).
Inputs: id (required), slug (required).
wafle_exports_customersARead-onlyIdempotent
Export the customer list of a store as CSV (default) or JSON. Includes email, name, phone, total spent, order count, last seen.
Use for CRM imports or general data exports. Wafle returns the raw CSV/JSON in the response body — for large stores prefer the dashboard download flow.
Inputs: slug (required), format, segment, min_orders.
wafle_exports_google_adsARead-onlyIdempotent
Export an audience formatted for Google Ads Customer Match: hashed email/phone with the column names Google expects.
Inputs: slug (required), segment, since_ts.
wafle_exports_meta_audienceARead-onlyIdempotent
Export an audience formatted for Meta (Facebook/Instagram) custom audiences: hashed email + phone per row, schema-compatible with Meta's CSV upload.
Filter by segment to build retargeting (high-intent, recovered, top-spenders) cohorts.
Inputs: slug (required), segment, since_ts, min_total_spent.
wafle_gateways_createA
Create a new gateway. Types:
mp_ar | mp_mx | mp_co | mp_cl: MercadoPago, requirescreds.access_token+creds.public_key.stripe: requirescreds.secret_key+creds.publishable_key.transfer: requiresmeta.cbu,meta.cbu_alias,meta.cbu_titular,meta.cbu_cuit.
After creating, run wafle_gateways_test to verify credentials before pointing a store at it.
Inputs: name (required), type (required), currency (required), meta, +4 more.
wafle_gateways_deleteADestructiveIdempotent
Delete a gateway. Fails if the gateway is currently the default for any store — switch the store first.
Destructive and irreversible. Confirm with the user.
Inputs: gateway_id (required).
wafle_gateways_listARead-onlyIdempotent
List all payment gateways across all stores (master view). Each gateway includes type, currency, active flag, store association.
Use to audit which stores have which gateways configured. Secrets are NEVER returned (only {set:true} markers).
Inputs: no named parameters.
wafle_gateways_testAIdempotent
Run a live credential test against the gateway provider. For MP it calls users/me; for Stripe it calls accounts/account; for transfer it returns ok.
Use after wafle_gateways_create or wafle_gateways_update (rotated creds). Read-only on the upstream provider.
Inputs: gateway_id (required).
wafle_gateways_updateAIdempotent
Patch an existing gateway. Use to rotate credentials (creds) or toggle active.
Destructive in the sense that an inactive gateway will reject new charges; live transactions in flight are unaffected.
Inputs: gateway_id (required), meta, name, creds, +2 more.
wafle_invitations_createA
Invite a teammate to a tenant by email. Sends an invitation email with a magic link.
Requires the actor to be owner or admin of the target tenant.
Inputs: role (required), email (required), tenant_id, tenant_slug.
wafle_members_listARead-onlyIdempotent
List all members of a tenant — accepted memberships + pending invitations. Requires owner or admin role.
Inputs: tenant_slug (required).
wafle_members_update_roleAIdempotent
Update a member's role / scopes / is_active for a given tenant. Requires owner role on the tenant.
Inputs: user_id (required), tenant_slug (required), role, scopes, +1 more.
wafle_orders_add_noteA
Add an internal or customer-visible note to an order. Notes appear in the timeline and (if customer=true) in the customer's order detail page + email.
Inputs: slug (required), text (required), order_id (required), customer_visible.
wafle_orders_cancelADestructiveIdempotent
Cancel an order. If the gateway supports auto-refund and the order was paid, wafle will trigger the refund.
Destructive: the order moves to cancelled and inventory is restocked. Confirm with the user before running.
Inputs: slug (required), order_id (required), reason, refund.
wafle_orders_createA
Manually create an order. Use only for migrations or telephone sales — normal orders flow from the storefront.
Body uses canonical snake_case shape: items[]+payment_method+gateway_id (see waffle-docs/API-CONVENTIONS.md). Idempotency-Key header is auto-set; safe to retry on transient errors.
Inputs: slug (required), items (required), customer (required), metadata, +4 more.
wafle_orders_getARead-onlyIdempotent
Fetch a single order by id. Returns customer, items, totals, gateway info, status, shipment data, timeline reference.
Inputs: slug (required), order_id (required).
wafle_orders_listARead-onlyIdempotent
List orders for a store with pagination + filters. Filters: status, date range, customer email, search.
Use this for any 'pendientes', 'enviados', 'últimos N días' style query. The response includes meta.gatewayId and meta.gatewayType so you can correlate with payment status.
Inputs: slug (required), page, email, to_ts, +4 more.
wafle_orders_refundADestructive
Refund a paid order, fully or partially. The refund is sent through whichever gateway captured the payment (MercadoPago / Stripe / manual transfer).
Destructive AND irreversible. Confirm amount before calling.
Inputs: slug (required), order_id (required), amount, reason.
wafle_orders_shipAIdempotent
Mark an order as shipped. Records the carrier, tracking number, and updates status to shipped.
Triggers the customer notification email if the store has it enabled.
Inputs: slug (required), carrier (required), order_id (required), tracking_number (required), +2 more.
wafle_orders_timelineARead-onlyIdempotent
Get the chronological timeline of an order: status changes, payment events, shipment, notes, refunds.
Use to audit how an order got into its current state.
Inputs: slug (required), order_id (required).
wafle_pixels_getARead-onlyIdempotent
Fetch the current marketing pixel IDs configured for a store: Meta (Facebook), TikTok, GA4, Google Ads.
Inputs: slug (required).
wafle_pixels_setAIdempotent
Set / update marketing pixel IDs of a store. Pass only the pixels you want to change; omit fields stay untouched. Pass null to clear a pixel.
Inputs: slug (required), ga4, meta, tiktok, +1 more.
wafle_pricing_compute_previewARead-onlyIdempotent
Compute the final price of a list of (sku, qty) pairs given the store's current rules. Returns base price, applied rules, final price.
Use as a sanity check before publishing pricing changes — answers 'how much would I be charging?' without disturbing the live cart.
Inputs: slug (required), items (required).
wafle_pricing_rules_createA
Create a new pricing rule. Types:
multiplier: catalog-wide markup (e.g. 2.2 = +120% on every base price).discount_tier: percentage discount when subtotal crosses a threshold.category_markup: per-category multiplier override.fixed_price: pin a specific SKU to a fixed price (overrides multiplier).
Always preview with wafle_pricing_compute_preview before committing rules in production.
Inputs: slug (required), type (required), value (required), label, +2 more.
wafle_pricing_rules_deleteADestructiveIdempotent
Delete a pricing rule by id. Irreversible — confirm before calling.
Inputs: slug (required), rule_id (required).
wafle_pricing_rules_listARead-onlyIdempotent
List all dynamic pricing rules of a store: catalog-wide multipliers, category markups, sale discount tiers, fixed prices on specific SKUs.
Use before editing — pricing rules compose, so you need to know what's already there.
Inputs: slug (required).
wafle_pricing_rules_updateBIdempotent
Patch an existing pricing rule by id.
Inputs: slug (required), rule_id (required), label, value, +1 more.
wafle_products_create_manualA
Manually create a product in a store whose catalog_mode = manual.
Do NOT use on stores with catalog_mode = supabase_sync — those products come from the upstream catalog and a manual create will be overwritten on next sync. For sync stores, use wafle_products_override to tweak fields without losing them on sync.
Inputs: sku (required), name (required), slug (required), price (required), +5 more.
wafle_products_getARead-onlyIdempotent
Fetch a single product by slug (the URL-friendly id). Returns full detail including variants, images, attributes and overrides.
Inputs: slug (required), product_slug (required).
wafle_products_listARead-onlyIdempotent
List products of a single store with pagination + optional search/filter. Returns id, slug, name, sku, price, stock, status, images.
Use to browse catalog or to find a product id before editing/overriding.
Inputs: slug (required), page, search, status, +2 more.
wafle_products_overrideAIdempotent
Set per-product overrides (price, name, description, images) that survive catalog syncs. Use on supabase_sync stores when you need to tweak a single product without forking the whole catalog.
Wafle stores overrides server-side and re-applies them after every sync.
Inputs: slug (required), overrides (required), product_id (required).
wafle_products_searchARead-onlyIdempotent
Lightweight search of products by name/sku. Equivalent to wafle_products_list with search set, but optimized for autocomplete.
Inputs: q (required), slug (required), limit.
wafle_products_sync_statusARead-onlyIdempotent
Get the status of a product-sync job (pending|running|done|failed). Pair with wafle_products_sync_trigger.
Inputs: job_id (required).
wafle_products_sync_triggerA
Trigger an asynchronous catalog sync for a store. Returns a job id; poll wafle_products_sync_status until done.
Only meaningful on catalog_mode = supabase_sync stores. On manual stores it's a no-op error.
Inputs: slug (required), mode.
wafle_products_sync_trigger_and_waitA
Trigger a catalog sync AND wait until it finishes (or 5min timeout). Emits MCP progress notifications during the wait — clients that support progress (Claude Desktop) show a live bar.
Use when the LLM wants to take an action after the sync is done. For fire-and-forget, use wafle_products_sync_trigger (returns immediately).
Inputs: slug (required), mode, timeout_seconds.
wafle_products_updateAIdempotent
Partial update of a product by numeric id. PATCH semantics — only the fields you pass change.
For sync stores, prefer wafle_products_override so the sync engine respects your tweaks.
Inputs: slug (required), product_id (required), name, price, +4 more.
wafle_prompts_listARead-onlyIdempotent
List the server-defined prompts available on this MCP server. Returns name, description, and argument schema for each. Useful for clients that don't surface the prompts/list MCP method.
Inputs: no named parameters.
wafle_resources_invalidateAIdempotent
Invalidate the in-memory MCP resource cache. Pass uri_pattern to drop matching entries (substring match), or omit to flush everything.
Master only. Use after a destructive write (mutating products, settings) if you want the next resources/read to fetch fresh data.
Inputs: uri_pattern.
wafle_shipping_carriers_statusARead-onlyIdempotent
Run the carrier connection self-test for a store. Hits each configured carrier API once and reports ok|degraded|down + latency.
Use when shipping rates are flaky or empty.
Inputs: slug (required).
wafle_shipping_rates_quoteARead-onlyIdempotent
Quote shipping rates for a destination + cart. Returns one row per available carrier (andreani, oca, viacargo, retiro, gratis) with cost + ETA.
Use as an estimate before checkout, or to debug 'why isn't carrier X showing up?'.
Inputs: slug (required), items (required), destination (required), subtotal.
wafle_stores_createA
Create a brand new wafle store. Required: slug, name, domain.
Use to onboard a new client. After creating, you'll typically run wafle_gateways_create, wafle_stores_settings_update, and either wafle_products_sync_trigger (for catalog-sync stores) or wafle_products_create_manual for manual catalogs.
DESTRUCTIVE side effect: also provisions a per-store API key, audit log entry, and a default gateway slot.
Inputs: name (required), slug (required), domain (required), currency, +2 more.
wafle_stores_getARead-onlyIdempotent
Fetch the full configuration of a single store. Includes payment gateway IDs (mp/stripe/transfer), shipping methods (andreani/oca/retiro), CBU/alias, social pixels, theme, abandoned-cart settings.
Use before editing settings — you need the current shape to send a delta.
Inputs: slug.
wafle_stores_listARead-onlyIdempotent
List all wafle stores the configured key can see. Each store includes id, slug, name, domain, brand color, payment + shipping config, gateway IDs, and customer-service contacts.
Use this as the first call when the user asks 'what stores does X have?' or before any per-store action — you'll need the slug.
Admin-only: per-tenant MCP clients only see their own store via wafle_stores_get.
Inputs: no named parameters.
wafle_stores_settings_getARead-onlyIdempotent
Alias of wafle_stores_get returning only the settings subtree (no items/orders). Convenient for review/diff workflows.
Inputs: slug.
wafle_stores_settings_updateAIdempotent
Update the store's settings subtree (operationally identical to wafle_stores_update today; provided as a stable name for the future split).
Inputs: settings (required), slug.
wafle_stores_updateAIdempotent
Update top-level store fields. Only the fields you pass are changed (PATCH semantics).
Common edits: theme_color, domain, free_shipping_from, payment_methods, shipping_methods. To change pixel/marketing IDs use wafle_pixels_set.
Inputs: cbu, name, slug, domain, +7 more.
wafle_system_audit_queryARead-onlyIdempotent
Query the audit log: who called what, when. Filter by store, actor type (master/store), endpoint, date range.
Use for forensics: 'who refunded order 87?', 'who toggled gateway 65 inactive?'.
Inputs: page, to_ts, from_ts, endpoint, +3 more.
wafle_system_healthARead-onlyIdempotent
Health snapshot of the wafle backend: db / redis / upstream catalog / WooCommerce core. Returns latency per check.
Use as a cheap first call when something looks off in production.
Inputs: no named parameters.
wafle_system_queue_failedARead-onlyIdempotent
List failed queue jobs with their last error. Pair with wafle_system_queue_retry.
Inputs: limit.
wafle_system_queue_retryAIdempotent
Retry a failed queue job by id, or all failed jobs of a kind.
Inputs: kind, job_id.
wafle_system_queue_statsARead-onlyIdempotent
Get the current background-queue stats: pending/running/done/failed counts, throughput, lag.
Use to debug 'why didn't my sync finish?' or to spot a backlog.
Inputs: no named parameters.
wafle_system_release_deployADestructive
Deploy a specific version of a component. Server-side this kicks off the deploy pipeline.
DESTRUCTIVE — touches production. Confirm with the user, run wafle_system_versions_list first, and prefer a staging deploy if available.
Inputs: version (required), component (required).
wafle_system_release_rollbackADestructive
Roll back a component to its previous deployed version. DESTRUCTIVE — confirm with the user.
Inputs: component (required).
wafle_system_stores_healthARead-onlyIdempotent
Per-store health: products count, orders in last 24h, errors, gateway connectivity. Heavier than wafle_system_health.
Inputs: no named parameters.
wafle_system_versions_listARead-onlyIdempotent
List the deployed versions of every wafle component (api, plugin, dashboard, themes). Use before deploying or rolling back.
Inputs: no named parameters.
wafle_users_meARead-onlyIdempotent
Return the currently-authenticated human's profile + memberships + current tenant.
Requires a session token (WAFLE_USER_SESSION). Will fail with 401 if the MCP is using a legacy API key.
Inputs: no named parameters.
wafle_users_memberships_listARead-onlyIdempotent
List the current human's memberships across all tenants. Returns each tenant's slug, name, role, and effective scopes.
Inputs: no named parameters.
wafle_users_switch_tenantAIdempotent
Set the session's current_tenant_id so subsequent calls without an explicit /stores/<slug>/ path apply to this tenant.
Returns the membership for the tenant. Errors with wafle_users_no_membership if the user is not a member.
Inputs: tenant_id (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 124 tools
Tool names largely map to distinct domains, and descriptions carefully distinguish similar operations (e.g. legacy vs new checkout orders, system_health vs stores_health). However, several near-duplicates exist: wafle_orders_list vs wafle_checkout_orders_list, wafle_orders_refund vs wafle_checkout_order_refund, wafle_abandoned_list vs wafle_checkout_cart_recover, plus explicit alias pairs for store settings. These are documented but could still cause misselection.
Almost all tools follow a consistent `wafle_<domain>_<resource>_<action>` snake_case pattern (products_list, coupons_update, agents_run). Minor deviations like wafle_users_me, wafle_auth_me, and wafle_ai_usage are predictable and do not seriously undermine the overall convention.
124 tools is far beyond the well-scoped range and creates significant agent tool-selection overhead. Even for a broad e-commerce platform, this is excessive and many endpoints could be consolidated or grouped behind sub-resources.
The platform covers the core e-commerce lifecycle extensively: stores, products, orders, coupons, customers, gateways, pricing, shipping, domains, ads, analytics, AI jobs, and agents. Notable gaps include product deletion, domain removal/detach, and some update operations, but most workflows have no dead ends.
Maintenance
Related MCP Connectors
Hosted WooCommerce MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Build, deploy and manage MaShop e-commerce projects from Claude, Cursor or any MCP client.
Hosted MCP for e-commerce: live product catalog, stock, and pricing for AI agents.
Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.
Related MCP Servers
- AlicenseBqualityDmaintenanceMCP server for managing WooCommerce stores through AI assistants like Claude. Provides 101 tools covering products, orders, customers, coupons, shipping, taxes, webhooks, settings, reports, and more.100112 npm2MIT
- AlicenseAqualityDmaintenanceMCP server for the negotiate.v1 protocol, enabling Claude to discover stores, list products, and negotiate deals through native tools.6MIT
- FlicenseNot gradedqualityDmaintenanceA proof of concept MCP server that gives AI agents business context for e-commerce operations including orders, inventory, logistics, returns, claims, and payments.1-
- FlicenseNot gradedqualityDmaintenanceA custom MCP server that turns Claude into an agentic shopping assistant for searching products, comparing options, managing a cart, and checking out with built-in guardrails for safe autonomous commerce.-