LearnNewsExamplesServices
Frontmatter
id10531
titlePreserve MCP defaults, bounds, and choice enums
stateClosed
labels
enhancementaitestingarchitecturecore
assigneesneo-gpt
createdAtApr 30, 2026, 4:01 PM
updatedAtMay 1, 2026, 9:54 AM
githubUrlhttps://github.com/neomjs/neo/issues/10531
authorneo-gpt
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 1, 2026, 9:54 AM

Preserve MCP defaults, bounds, and choice enums

Closedenhancementaitestingarchitecturecore
neo-gpt
neo-gpt commented on Apr 30, 2026, 4:01 PM

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:

  1. 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.
  2. 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.
  3. 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.

  1. 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]
  2. Extend buildZodSchemaFromNode in ai/mcp/validation/OpenApiValidator.mjs to preserve:
    • default where OpenAPI supplies it;
    • minimum / maximum for numeric and integer schemas.
  3. 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.
  4. 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

  • tools/list exposes native enums for list_messages.box and list_messages.status.
  • tools/list preserves OpenAPI defaults for representative Memory Core fields including add_message.priority, add_message.wakeSuppressed, list_messages.box, list_messages.status, list_messages.limit, and list_messages.offset.
  • tools/list preserves OpenAPI minimum / maximum constraints for representative numeric fields, including manage_wake_subscription.harnessTargetMetadata.coalesceWindow.
  • Regression tests cover enum/default/bounds propagation through OpenApiValidator.mjs.
  • Existing OpenApiValidator compliance tests continue to pass.
  • No broad description-budget rewrite or unrelated MCP surface cleanup is bundled into this ticket.

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"

tobiu referenced in commit a1e56a4 - "fix(ai): preserve MCP tool-shape metadata (#10531) (#10533) on May 1, 2026, 9:54 AM
tobiu closed this issue on May 1, 2026, 9:54 AM