Summary
fieldTypeSchema in src/schema/app/form-layout.ts accepts 5 values that the kintone REST API does not allow at layout[].fields[].type: GROUP, SUBTABLE, STATUS, STATUS_ASSIGNEE, and CATEGORY.
This is not merely cosmetic. GROUP and SUBTABLE are row types (layout[].type), so presenting them as field types leads callers to place a group inside a row. Such a payload passes validation unchanged and is forwarded to kintone, which rejects it with [400] [CB_VA01] Missing or invalid input. — an error that gives the caller no indication of the actual cause.
Affected via layoutForParameterSchema:
kintone-update-form-layout (inputSchema)
kintone-get-form-layout (outputSchema)
Target Version
v1.9.1
Reproduction
Call kintone-update-form-layout with a group placed inside a row — a shape the current schema presents as valid:
{
"app": "1",
"layout": [
{ "type": "ROW", "fields": [ { "type": "GROUP", "code": "group_0" } ] }
]
}
type: "GROUP" is an accepted member of fieldTypeSchema and code is a string, so validation passes. The callback forwards layout verbatim to client.app.updateFormLayout(), and kintone responds [400] [CB_VA01] Missing or invalid input. The same applies to SUBTABLE, STATUS, STATUS_ASSIGNEE, and CATEGORY.
An additional note on the more natural payload: a caller that treats GROUP as a field type will usually also supply the group's contents:
{ "type": "ROW", "fields": [ { "type": "GROUP", "code": "group_0", "layout": [ /* rows */ ] } ] }
Here layout is not declared on fieldForParameterSchema, and since z.object() in zod 3.25.76 strips unknown keys by default, it is silently dropped rather than reported — leaving the same invalid { "type": "GROUP", "code": "group_0" } to be sent to kintone.
Expected Behavior
layout[].fields[].type should accept only the 26 values documented for both endpoints:
CALC CHECK_BOX CREATED_TIME CREATOR DATE DATETIME DROP_DOWN FILE GROUP_SELECT HR LABEL LINK MODIFIER MULTI_LINE_TEXT MULTI_SELECT NUMBER ORGANIZATION_SELECT RADIO_BUTTON RECORD_NUMBER REFERENCE_TABLE RICH_TEXT SINGLE_LINE_TEXT SPACER TIME UPDATED_TIME USER_SELECT
A group should only be expressible as a row-level element, which the schema already supports correctly via groupLayoutForParameterSchema.
Actual Behavior
fieldTypeSchema declares 31 literals. The 5 extras are:
| Value |
Why it is not valid at layout[].fields[].type |
GROUP |
A row type (layout[].type), not a field type |
SUBTABLE |
A row type (layout[].type), not a field type |
STATUS |
Not placed on the form layout |
STATUS_ASSIGNEE |
Not placed on the form layout |
CATEGORY |
Not placed on the form layout |
Invalid input is accepted at the MCP boundary and only surfaces later as an opaque kintone error.
Suggested fix
Remove the 5 literals from fieldTypeSchema so it matches the 26 documented values.
This is safe for kintone-get-form-layout's outputSchema as well: the Get Form Layout response spec documents the same 26 values, so kintone never returns the removed literals at this position.
This change alone also resolves the silent-drop case described above — once GROUP is no longer an accepted field type, { "type": "GROUP", "code": "...", "layout": [...] } inside fields[] fails immediately on the type literal instead of being partially stripped and forwarded.
Environment
- Operating System: macOS 26.6.1 (arm64)
- Node.js version: v26.2.0
- pnpm version: 11.18.0
- @kintone/mcp-server: 1.9.1 (run via `pnpm dlx @kintone/mcp-server`)
- MCP client: Claude Code
Summary
fieldTypeSchemainsrc/schema/app/form-layout.tsaccepts 5 values that the kintone REST API does not allow atlayout[].fields[].type:GROUP,SUBTABLE,STATUS,STATUS_ASSIGNEE, andCATEGORY.This is not merely cosmetic.
GROUPandSUBTABLEare row types (layout[].type), so presenting them as field types leads callers to place a group inside a row. Such a payload passes validation unchanged and is forwarded to kintone, which rejects it with[400] [CB_VA01] Missing or invalid input.— an error that gives the caller no indication of the actual cause.Affected via
layoutForParameterSchema:kintone-update-form-layout(inputSchema)kintone-get-form-layout(outputSchema)Target Version
v1.9.1
Reproduction
Call
kintone-update-form-layoutwith a group placed inside a row — a shape the current schema presents as valid:{ "app": "1", "layout": [ { "type": "ROW", "fields": [ { "type": "GROUP", "code": "group_0" } ] } ] }type: "GROUP"is an accepted member offieldTypeSchemaandcodeis a string, so validation passes. The callback forwardslayoutverbatim toclient.app.updateFormLayout(), and kintone responds[400] [CB_VA01] Missing or invalid input.The same applies toSUBTABLE,STATUS,STATUS_ASSIGNEE, andCATEGORY.An additional note on the more natural payload: a caller that treats
GROUPas a field type will usually also supply the group's contents:{ "type": "ROW", "fields": [ { "type": "GROUP", "code": "group_0", "layout": [ /* rows */ ] } ] }Here
layoutis not declared onfieldForParameterSchema, and sincez.object()in zod 3.25.76 strips unknown keys by default, it is silently dropped rather than reported — leaving the same invalid{ "type": "GROUP", "code": "group_0" }to be sent to kintone.Expected Behavior
layout[].fields[].typeshould accept only the 26 values documented for both endpoints:CALCCHECK_BOXCREATED_TIMECREATORDATEDATETIMEDROP_DOWNFILEGROUP_SELECTHRLABELLINKMODIFIERMULTI_LINE_TEXTMULTI_SELECTNUMBERORGANIZATION_SELECTRADIO_BUTTONRECORD_NUMBERREFERENCE_TABLERICH_TEXTSINGLE_LINE_TEXTSPACERTIMEUPDATED_TIMEUSER_SELECTA group should only be expressible as a row-level element, which the schema already supports correctly via
groupLayoutForParameterSchema.Actual Behavior
fieldTypeSchemadeclares 31 literals. The 5 extras are:layout[].fields[].typeGROUPlayout[].type), not a field typeSUBTABLElayout[].type), not a field typeSTATUSSTATUS_ASSIGNEECATEGORYInvalid input is accepted at the MCP boundary and only surfaces later as an opaque kintone error.
Suggested fix
Remove the 5 literals from
fieldTypeSchemaso it matches the 26 documented values.This is safe for
kintone-get-form-layout'soutputSchemaas well: the Get Form Layout response spec documents the same 26 values, so kintone never returns the removed literals at this position.This change alone also resolves the silent-drop case described above — once
GROUPis no longer an accepted field type,{ "type": "GROUP", "code": "...", "layout": [...] }insidefields[]fails immediately on thetypeliteral instead of being partially stripped and forwarded.Environment