Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Target `dev` first for new documentation or generated-spec improvements unless t

The MCP artifact (`openapi-v3.0.mcp.yaml`) is built from the formz service contract fetched with `?version=mcp-1.0`, merged with the other services (which stay on `?version=3.0`). Endpoint description Markdown files are shared with the public build and keep resolving from `spec/docs/v3.0/`; `scripts/fetch-specs.mjs` rewrites any `docs/mcp-1.0/` references in the fetched mcp-1.0 contract to `docs/v3.0/`, so no separate Markdown set exists for MCP. The public artifact (`openapi-v3.0.yaml`) continues to use the formz `?version=3.0` contract.

While the upstream `mcp-1.0` contract is being rolled out, `scripts/backfill-mcp-operations.mjs` copies validator-required operations that are missing from the `mcp-1.0` merge (for example `formsRetrieve`, `formsPartialUpdate`, `fieldsPartialUpdate`) from the formz v3.0 bundle and logs each backfilled operation. The step is a no-op once the upstream contract exposes them; remove the script when the rollout is complete.
While the upstream `mcp-1.0` contract is being rolled out, `scripts/backfill-mcp-operations.mjs` copies validator-required operations that are missing from the `mcp-1.0` merge (for example `formsRetrieve`, `formsPartialUpdate`, `formsDestroy`, `fieldsCreate`, `fieldsRetrieve`, `fieldsDestroy`, `fieldsPartialUpdate`) from the formz v3.0 bundle and logs each backfilled operation. The step is a no-op once the upstream contract exposes them; remove the script when the rollout is complete.

The MCP artifact should stay accurate for direct API users and easy to use for MCP/CLI clients:

Expand Down
4 changes: 4 additions & 0 deletions scripts/backfill-mcp-operations.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const requiredOperationIds = new Set([
"boardsList",
"formsCreate",
"formsPartialUpdate",
"formsDestroy",
"fieldsRetrieve",
"fieldsCreate",
"fieldsDestroy",
"formsRowsCreate",
"themesList",
"themesCreate",
Expand Down
145 changes: 145 additions & 0 deletions scripts/build-mcp-openapi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,34 @@ const coreMcpOperations = {
}
}
},
formsDestroy: {
summary: "Delete a form",
description:
"Deletes a form and its submission data from the active workspace. Use this only after confirming the exact form slug with the user; deleting a form is permanent and different from disconnecting it from an app or board.",
parameterDescriptions: {
slug: "Form slug to delete."
},
mcp: {
tool_name: "delete_form",
aliases: ["remove_form", "destroy_form", "delete_form_by_slug"],
intent: "Delete one Formaloo form and its submitted data.",
requires_workspace: true,
read_only: false,
destructive: true,
idempotent: false,
result_path: "data.data",
user_data: true,
requires_confirmation: true
},
responseExamples: {
"200": {
deleted_form: {
summary: "Deleted form",
value: {}
}
}
}
},
formFieldsRetrieve: {
summary: "Get editable form and fields",
description:
Expand Down Expand Up @@ -1005,6 +1033,123 @@ const coreMcpOperations = {
requires_confirmation: true
}
},
fieldsRetrieve: {
summary: "Get one field by slug",
description:
"Retrieves one existing field by slug. Use this when the task is truly about one field. For form authoring, reshaping, ordering, logic-aware edits, or any change that depends on sibling fields and choices, start with the joint form-and-fields read (`formFieldsRetrieve`) because it returns the surrounding field list, ordering, choice slugs, aliases, and form settings needed for coordinated updates.",
parameterDescriptions: {
slug: "Field slug."
},
mcp: {
tool_name: "get_field",
aliases: ["show_field", "field_details", "get_form_field"],
intent: "Get one Formaloo field by slug when the task does not need full form-builder context.",
requires_workspace: true,
read_only: true,
destructive: false,
idempotent: true,
result_path: "data.data.field",
user_data: false,
requires_confirmation: false
},
responseExamples: {
"200": {
field: {
summary: "Field details",
value: {
slug: "short_text_abc123",
type: "short_text",
title: "Name",
alias: "name",
required: true
}
}
}
}
},
fieldsCreate: {
summary: "Create one field",
description:
"Creates one field on an existing form. This is appropriate for a simple single-field add. For normal form authoring, new forms, multi-field edits, ordering, removals, logic, or same-request field/choice references, start with the joint form-and-fields flow (`formFieldsRetrieve` then `formFieldsPartialUpdate`, or composed `create_form`/`update_form` tools) so the full form structure is updated together.",
mcp: {
tool_name: "create_field",
aliases: ["add_field", "create_form_field", "new_field"],
intent: "Create one Formaloo field on an existing form when a coordinated form-builder update is unnecessary.",
requires_workspace: true,
read_only: false,
destructive: false,
idempotent: false,
result_path: "data.data.field",
user_data: false,
requires_confirmation: true
},
requestExamples: {
create_short_text_field: {
summary: "Create a short text field",
value: {
form: "customer-feedback",
type: "short_text",
title: "Name",
alias: "name",
required: true
}
},
create_choice_field: {
summary: "Create a choice field",
value: {
form: "customer-feedback",
type: "choice",
title: "How satisfied are you?",
choice_items: [
{ title: "Happy" },
{ title: "Needs help" }
]
}
}
},
responseExamples: {
"201": {
created_field: {
summary: "Created field",
value: {
slug: "short_text_abc123",
type: "short_text",
title: "Name",
alias: "name",
required: true
}
}
}
}
},
fieldsDestroy: {
summary: "Delete one field",
description:
"Deletes one existing field. This is appropriate for a confirmed single-field deletion. For coordinated removals, reordering, or updates that must preserve the rest of the form structure, start with the joint form-and-fields update (`formFieldsPartialUpdate`). Confirm the exact field slug with the user before deleting; deleting a field may affect existing logic or integrations.",
parameterDescriptions: {
slug: "Field slug to delete."
},
mcp: {
tool_name: "delete_field",
aliases: ["remove_field", "destroy_field", "delete_form_field"],
intent: "Delete one Formaloo field when a coordinated form-builder update is unnecessary.",
requires_workspace: true,
read_only: false,
destructive: true,
idempotent: false,
result_path: "data.data",
user_data: false,
requires_confirmation: true
},
responseExamples: {
"200": {
deleted_field: {
summary: "Deleted field",
value: {}
}
}
}
},
formsRowsCreate: {
summary: "Create a form row or submission",
description:
Expand Down
4 changes: 4 additions & 0 deletions scripts/validate-mcp-openapi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const coreOperationIds = [
"boardsList",
"formsCreate",
"formsPartialUpdate",
"formsDestroy",
"fieldsRetrieve",
"fieldsCreate",
"fieldsDestroy",
"formsRowsCreate"
];
const requiredMcpReadyOperationIds = [
Expand Down
Loading