Problem
The MCP tool surface can do everything to a site's content but nothing to its schema. Rows are fully covered — content_create_document, content_set_document_field(s), content_set_document_status, content_delete_document — and the schema can be read via content_get_collection_schema. There is no matching write operation: nothing in server/ai/tools/content/writeTools.ts (or anywhere under server/ai/tools/) creates a table or adds a field.
That read/write asymmetry is the single manual break in an otherwise fully automatable pipeline. Migrating a real 10-page site onto Instatic, everything ran over MCP — 62 media items mapped, 63 rows created and published, loops wired, HTML inserted, node props set, CSS applied, pages published and verified against the live HTML — except the schema step. Four custom tables (kunden, referenzen, anfragen, news) and their ~30 fields had to be typed by hand in the Data workspace, with the agent stopping and waiting in the middle of the run.
The consequence is not just typing effort. It means agent-driven setup can never be reproduced: there is no way to provision the same schema on a second site, to rebuild a staging site from a spec, or to re-run a migration end to end.
Proposed solution
Two write tools that wrap the handlers already doing this work for the Data workspace:
content_create_collection({ name, slug?, kind?, singularLabel?, pluralLabel?, routeBase?, primaryFieldId?, fields? }) → the existing POST ${CMS_API_PREFIX}/data/tables path (server/handlers/cms/data/tables.ts, handleTablesCollection), which already validates against TableCreateBodySchema, derives labels and slug, calls createDataTable(...) and records data.table.create in the audit log.
content_update_collection_schema({ collectionId, fields }) — or a narrower content_add_field({ collectionId, field }) — over the existing table-item PATCH, which already does update.fields = normalizeDataTableFields(body.fields) and refuses to touch frozen system-table built-ins.
Both are thin wrappers: validation (DataFieldSchema / normalizeDataTableFields), the built-in-field guards, and audit recording all exist. Returning the resulting table (including the actual field IDs as stored) matters most in practice — an agent needs to read back what it got before wiring loops against it.
Worth gating behind its own capability so a content-only MCP connector cannot reshape tables; server/ai/tools/capabilityGate.ts already provides the mechanism.
Alternatives considered
- Create tables by hand once, then automate the rest. This is the current workaround and it does work — it is what I did. It breaks down as soon as the schema has to exist more than once, and it forces a human into the middle of an agent run rather than at its boundaries.
- Drive the admin REST API directly instead of MCP. Possible, but it needs session credentials the MCP connector already holds, and it bypasses the capability gate and audit path that MCP writes go through.
- Only add
content_add_field, not table creation. Smaller, and it would cover schema evolution on an existing site, but the first-run case (a new site, no tables yet) is exactly the one that needs it most.
Related: #416 makes the same point for the media/code-asset lifecycle — the pattern is that MCP's read surface is broad while a few write operations are missing, and each gap forces a manual detour.
Area
AI
Observed on main @ a0b1e4e5, deployed on Railway. Happy to open a PR if you'll say which shape you prefer — a single content_update_collection_schema taking the whole field array, or a narrower content_add_field.
🤖 Generated with Claude Code
Problem
The MCP tool surface can do everything to a site's content but nothing to its schema. Rows are fully covered —
content_create_document,content_set_document_field(s),content_set_document_status,content_delete_document— and the schema can be read viacontent_get_collection_schema. There is no matching write operation: nothing inserver/ai/tools/content/writeTools.ts(or anywhere underserver/ai/tools/) creates a table or adds a field.That read/write asymmetry is the single manual break in an otherwise fully automatable pipeline. Migrating a real 10-page site onto Instatic, everything ran over MCP — 62 media items mapped, 63 rows created and published, loops wired, HTML inserted, node props set, CSS applied, pages published and verified against the live HTML — except the schema step. Four custom tables (
kunden,referenzen,anfragen,news) and their ~30 fields had to be typed by hand in the Data workspace, with the agent stopping and waiting in the middle of the run.The consequence is not just typing effort. It means agent-driven setup can never be reproduced: there is no way to provision the same schema on a second site, to rebuild a staging site from a spec, or to re-run a migration end to end.
Proposed solution
Two write tools that wrap the handlers already doing this work for the Data workspace:
content_create_collection({ name, slug?, kind?, singularLabel?, pluralLabel?, routeBase?, primaryFieldId?, fields? })→ the existingPOST ${CMS_API_PREFIX}/data/tablespath (server/handlers/cms/data/tables.ts,handleTablesCollection), which already validates againstTableCreateBodySchema, derives labels and slug, callscreateDataTable(...)and recordsdata.table.createin the audit log.content_update_collection_schema({ collectionId, fields })— or a narrowercontent_add_field({ collectionId, field })— over the existing table-itemPATCH, which already doesupdate.fields = normalizeDataTableFields(body.fields)and refuses to touch frozen system-table built-ins.Both are thin wrappers: validation (
DataFieldSchema/normalizeDataTableFields), the built-in-field guards, and audit recording all exist. Returning the resulting table (including the actual field IDs as stored) matters most in practice — an agent needs to read back what it got before wiring loops against it.Worth gating behind its own capability so a content-only MCP connector cannot reshape tables;
server/ai/tools/capabilityGate.tsalready provides the mechanism.Alternatives considered
content_add_field, not table creation. Smaller, and it would cover schema evolution on an existing site, but the first-run case (a new site, no tables yet) is exactly the one that needs it most.Related: #416 makes the same point for the media/code-asset lifecycle — the pattern is that MCP's read surface is broad while a few write operations are missing, and each gap forces a manual detour.
Area
AI
Observed on
main@a0b1e4e5, deployed on Railway. Happy to open a PR if you'll say which shape you prefer — a singlecontent_update_collection_schemataking the whole field array, or a narrowercontent_add_field.🤖 Generated with Claude Code