Context
After PR #10528 merged, OpenApiValidator.mjs now correctly propagates string enum values from OpenAPI YAML into MCP tools/list JSON Schemas. A follow-up audit using the live Memory Core server showed that this closed the enum gap only for fields that already declare native enum arrays in YAML.
Empirical command used for the audit:
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node ai/mcp/server/memory-core/mcp-server.mjs
On merged origin/dev, native enums now appear for surfaces such as add_message.priority, transition_task.newState, manage_wake_subscription.action, manage_wake_subscription.trigger, manage_wake_subscription.filters.priority, and manage_wake_subscription.harnessTarget.
The Problem
The MCP tool shapes still miss valuable schema information that is present or implied in ai/mcp/server/memory-core/openapi.yaml:
- Some choice fields still encode their valid values only in prose descriptions, so the native tool shape cannot expose them as enums.
list_messages.box says 'inbox', 'outbox', 'all' in prose, but has no YAML enum.
list_messages.status says 'all', 'read', 'unread' in prose, but has no YAML enum.
- OpenAPI
default values are dropped during OpenAPI -> Zod -> JSON Schema translation.
- Examples in YAML:
add_message.priority: normal, add_message.wakeSuppressed: false, list_messages.box: inbox, list_messages.status: all, list_messages.limit: 50, list_messages.offset: 0.
- OpenAPI numeric bounds are dropped during translation.
- Example:
manage_wake_subscription.harnessTargetMetadata.coalesceWindow has minimum: 0, maximum: 300 in YAML, but tools/list only exposes {type: integer}.
- Similar bounds exist for summary-search result limits and quality/productivity/impact/complexity output scores.
This keeps agents dependent on prose parsing for values that should be native machine-readable constraints.
The Architectural Reality
ai/mcp/validation/OpenApiValidator.mjs owns the OpenAPI-to-Zod mapping used by MCP tool registration. PR #10528 added string enum support in buildZodSchemaFromNode, but the same translator still does not map default, minimum, or maximum into the generated Zod schema.
The substrate split is important:
- Missing enum declarations for
list_messages.box/status belong in ai/mcp/server/memory-core/openapi.yaml because the source contract lacks native enum metadata.
- Dropped
default, minimum, and maximum values belong in ai/mcp/validation/OpenApiValidator.mjs because the YAML already carries those fields and the translator loses them.
zod-to-json-schema can emit these constraints when the Zod schema includes them; this was verified with a local node -e probe using .default(), .min(), and .max().
The Fix
Keep this scoped to schema fidelity, not a broad MCP cleanup.
- Add native
enum arrays to Memory Core YAML for prose-only choice fields:
list_messages.box: [inbox, outbox, all]
list_messages.status: [all, read, unread]
- Extend
buildZodSchemaFromNode in ai/mcp/validation/OpenApiValidator.mjs to preserve:
default where OpenAPI supplies it;
minimum / maximum for numeric and integer schemas.
- Add targeted regression coverage in
test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjs proving the generated schema includes:
- enum values for
list_messages.box/status;
- defaults for representative string/enum/boolean/integer fields;
- numeric bounds for representative integer fields such as
coalesceWindow.
- Use the fresh MCP server invocation (
tools/list via node ai/mcp/server/memory-core/mcp-server.mjs) as empirical verification after implementation.
Acceptance Criteria
Out of Scope
- Rewriting all Memory Core tool descriptions.
- Changing MCP server runtime behavior beyond tool schema generation and validation metadata.
- Supporting non-string enums beyond the already-scoped OpenAPI/Zod constraints unless a test proves the existing path requires it.
- Changing output-schema leniency or open-bag object behavior from prior tickets.
Avoided Traps
- Trap: Put valid values into prose descriptions. Rejected because agents should receive machine-readable constraints, not parse English.
- Trap: Treat this as a Memory Core-only bug. Rejected because
default and numeric bounds are lost in the shared OpenAPI validator and can affect other MCP servers too.
- Trap: Combine with a global MCP description cleanup. Rejected because description budget work is adjacent but separately scoped.
Related
- #10527 / PR #10528 — added string enum propagation through
OpenApiValidator.mjs.
- #10041 — MCP tool limit/schema budget guardrails.
- #10407 — prior strict-schema stripping issue on
manage_wake_subscription metadata.
- #10248 — stale MCP tool-shape verification context.
Origin Session ID: abb9e613-9465-4097-b9a9-30d30f8997a6
Retrieval Hint: "tools/list OpenApiValidator default minimum maximum list_messages box status coalesceWindow"
Context
After PR #10528 merged,
OpenApiValidator.mjsnow correctly propagates stringenumvalues from OpenAPI YAML into MCPtools/listJSON Schemas. A follow-up audit using the live Memory Core server showed that this closed the enum gap only for fields that already declare nativeenumarrays in YAML.Empirical command used for the audit:
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node ai/mcp/server/memory-core/mcp-server.mjsOn merged
origin/dev, native enums now appear for surfaces such asadd_message.priority,transition_task.newState,manage_wake_subscription.action,manage_wake_subscription.trigger,manage_wake_subscription.filters.priority, andmanage_wake_subscription.harnessTarget.The Problem
The MCP tool shapes still miss valuable schema information that is present or implied in
ai/mcp/server/memory-core/openapi.yaml:list_messages.boxsays'inbox', 'outbox', 'all'in prose, but has no YAMLenum.list_messages.statussays'all', 'read', 'unread'in prose, but has no YAMLenum.defaultvalues are dropped during OpenAPI -> Zod -> JSON Schema translation.add_message.priority: normal,add_message.wakeSuppressed: false,list_messages.box: inbox,list_messages.status: all,list_messages.limit: 50,list_messages.offset: 0.manage_wake_subscription.harnessTargetMetadata.coalesceWindowhasminimum: 0,maximum: 300in YAML, buttools/listonly exposes{type: integer}.This keeps agents dependent on prose parsing for values that should be native machine-readable constraints.
The Architectural Reality
ai/mcp/validation/OpenApiValidator.mjsowns the OpenAPI-to-Zod mapping used by MCP tool registration. PR #10528 added string enum support inbuildZodSchemaFromNode, but the same translator still does not mapdefault,minimum, ormaximuminto the generated Zod schema.The substrate split is important:
list_messages.box/statusbelong inai/mcp/server/memory-core/openapi.yamlbecause the source contract lacks native enum metadata.default,minimum, andmaximumvalues belong inai/mcp/validation/OpenApiValidator.mjsbecause the YAML already carries those fields and the translator loses them.zod-to-json-schemacan emit these constraints when the Zod schema includes them; this was verified with a localnode -eprobe using.default(),.min(), and.max().The Fix
Keep this scoped to schema fidelity, not a broad MCP cleanup.
enumarrays to Memory Core YAML for prose-only choice fields:list_messages.box:[inbox, outbox, all]list_messages.status:[all, read, unread]buildZodSchemaFromNodeinai/mcp/validation/OpenApiValidator.mjsto preserve:defaultwhere OpenAPI supplies it;minimum/maximumfor numeric and integer schemas.test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjsproving the generated schema includes:list_messages.box/status;coalesceWindow.tools/listvianode ai/mcp/server/memory-core/mcp-server.mjs) as empirical verification after implementation.Acceptance Criteria
tools/listexposes native enums forlist_messages.boxandlist_messages.status.tools/listpreserves OpenAPI defaults for representative Memory Core fields includingadd_message.priority,add_message.wakeSuppressed,list_messages.box,list_messages.status,list_messages.limit, andlist_messages.offset.tools/listpreserves OpenAPIminimum/maximumconstraints for representative numeric fields, includingmanage_wake_subscription.harnessTargetMetadata.coalesceWindow.OpenApiValidator.mjs.Out of Scope
Avoided Traps
defaultand numeric bounds are lost in the shared OpenAPI validator and can affect other MCP servers too.Related
OpenApiValidator.mjs.manage_wake_subscriptionmetadata.Origin Session ID: abb9e613-9465-4097-b9a9-30d30f8997a6
Retrieval Hint: "tools/list OpenApiValidator default minimum maximum list_messages box status coalesceWindow"