@awesomate/hosting-mcp
Version:
Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases
106 lines (86 loc) • 5.64 kB
Markdown
# Datatables — client-side playbook
n8n data tables: small operational stores a workflow reads/writes at runtime.
Read with `awesomate_n8n_inspect {what: "datatables"}` (tables, columns, row
counts). Write with `awesomate_n8n_datatable_write` (Support Plus+ plans only).
## Right store or wrong store
| Data | Store |
|---|---|
| Dedupe ledger (seen event ids, sent emails) | Datatable |
| Task queue / retry list a workflow drains | Datatable |
| Lookup map (SKU→label, email→owner) | Datatable |
| Cursor/state between runs (last-synced timestamp) | Datatable |
| Real app data (users, orders, content) | The app's own database — never a datatable |
| Analytics, event history, anything unbounded | External store (app DB, sheet, warehouse) |
Rule of thumb: bounded row count, flat rows, no joins, consumed by the
automation itself. Instance cap is 50 tables (`datatable_cap_reached`), and
creates have a daily plan quota (`quota_exceeded` — limits in
`awesomate_n8n_context`).
## Creating — pass workflowId
```
awesomate_n8n_datatable_write {action: "create", name, columns: [{name, type?}], workflowId}
```
- **Datatables resolve PER PROJECT at runtime.** A workflow in project A
referencing a table in project B fails on every run with
`Could not find the data table: '<id>'` — while the table, its columns, and
permissions are all perfectly intact. When the id matches and structure
looks fine, the project link is what's broken.
- **Pass `workflowId` whenever the table serves a specific workflow** (nearly
always). The table is then moved into that workflow's owner project —
co-location is verified, never assumed.
- Without `workflowId` the server co-locates only when exactly one project
owns your Claude Code drafts. Otherwise the response carries a
`projectWarning` ("CLI drafts span N projects — pass workflowId…" or
"workflowId … has no owner project — table left where n8n placed it").
**Treat `projectWarning` as a failed co-location**: recreate with the right
`workflowId` before inserting any rows.
- Column `type`: `string` | `number` | `boolean` | `date` (default `string`).
Column names: letters/digits/underscores, starting with a letter, no
spaces — n8n's row API references columns bare, so a spaced name is
unwritable even though PG would accept it.
- Design the full column set up front — schema is effectively frozen (next
section).
## Schema is immutable over REST
n8n's REST API cannot alter a table. `action: "add_column"` exists but runs a
direct database write, so it additionally requires the account's
`allow_pg_writes` consent — ON by default, and NOT client-toggleable: a
`consent_required` here means Awesomate disabled it for this account, so the
remediation is recreating the table with the full column set, or asking
Awesomate support to re-enable direct database writes.
There is no rename, drop, or retype at all. Wrong schema and no PG consent →
create a new table, migrate rows, repoint the workflow.
## Writes only touch self-created tables
`insert` / `update` / `delete_rows` / `add_column` work only on tables created
through Claude Code. Anything else → `403 not_self_created` — including tables
provisioned by Awesomate template deploys. Those belong to managed
automations; do not work around the refusal. Reads are unrestricted:
`awesomate_n8n_inspect` lists every table.
## Row operations
| action | Requires | Notes |
|---|---|---|
| `insert` | `rows`: 1–100 objects | Chunk larger batches |
| `update` | non-empty `filter` + `data` object | `data` is one object, not an array |
| `delete_rows` | non-empty `filter` — REQUIRED | There is deliberately no delete-all. To empty a table, delete by filter or recreate it |
## The dedupe gate pattern (rowNotExists)
Insert-if-absent as a barrier before side effects — the main reason a
datatable exists in a client workflow:
1. Table with one key column (e.g. `event_id` string) plus any audit columns.
2. In the workflow, BEFORE the side effect (email, API call, charge): Data
table node with the **row-does-not-exist** operation matching the key —
only unseen items pass.
3. Insert the key immediately after the gate, BEFORE the side effect.
Insert-first gives at-most-once (right for emails and charges);
insert-after gives at-least-once (duplicates on crash/retry).
4. The gate and insert are separate node steps, not a transaction — a webhook
delivered twice in the same instant can pass both. Acceptable for dedupe;
not a locking primitive.
Queue-drain workflows (`splitInBatches` over a table) need `executionTimeout`
set, and `saveExecutionProgress` stays FALSE — both fleet invariants.
## Failure decode
| Symptom | Meaning | Fix |
|---|---|---|
| `Could not find the data table: '<id>'` at runtime | Project scope, not existence | Recreate/move the table with `workflowId`; check `awesomate_n8n_inspect {what: "datatables"}` vs the workflow's project |
| `403 not_self_created` | Table wasn't created through Claude Code | Create your own table; never write agency tables |
| `consent_required` on add_column | `allow_pg_writes` disabled for this account (not client-toggleable) | Recreate with the full schema, or ask Awesomate support |
| `409 column_exists` | Column name collision | Pick another name; check current columns via inspect |
| `429 datatable_cap_reached` / `quota_exceeded` | 50-table cap or daily create quota | Stop; reuse or delete tables, or wait for the daily reset |
| `501 datatables_unsupported` | Instance's n8n version predates data tables | No datatable path — use an external store |