Skip to content

fix: preserve scalar enum and const constraints in MCP schemas - #300

Open
liangzhechen655 wants to merge 3 commits into
Eigenwise:mainfrom
liangzhechen655:fix/mcp-scalar-value-constraints
Open

liangzhechen655 wants to merge 3 commits into
Eigenwise:mainfrom
liangzhechen655:fix/mcp-scalar-value-constraints

Conversation

@liangzhechen655

@liangzhechen655 liangzhechen655 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

MCP tool parameters with scalar enum or const values lose their choices during schema conversion. The generated input model accepts values outside the advertised choices, and the model-facing schema omits the restrictions.

Represent scalar choices with Literal, intersect them with the declared JSON type, and validate that type before literal matching. This keeps null out of a string-only enum, rejects strings in integer enums, and distinguishes booleans from numbers. Nullable type arrays retain null when explicitly allowed. Definitions with no compatible scalar choices raise a clear error instead of becoming unrestricted fields.

Referenced choices use the resolver already merged in #304; this PR's remaining source diff only adds scalar constraints to that implementation.

Validation on Windows / Python 3.13:

  • All 11 original regressions failed on the original base. All 10 additional type-intersection regressions failed on the previous PR head.
  • Full core suite: 421 passed, 3 credential-gated integration tests skipped, 93% total coverage.
  • Repository-wide Black and Flake8 checks pass.
  • GitHub's Code Quality & Tests check passed on 6dbfbe4.
  • No live provider integration run is claimed.

@Eigenwise Eigenwise left a comment •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source review of 73963771fbfcd18a45b8bf61d0f0c3f8fdb56ee8: schema_transformer.py:103-108 returns a Literal before applying the declared field type. A required string field with enum: ["brief", null] now includes null, and an integer field with enum: [1, "two"] includes a string. Preserve the intersection of the declared type and choices, and test both typed mixed-enum cases in validation and the emitted schema.

The reference-resolution change overlaps #304. Retain one implementation of that branch when reconciling the two. This correctness finding is source-derived; I haven't run this head's tests locally.

The earlier complexity-only rework request is withdrawn.

…constraints

# Conflicts:
#	atomic-agents/atomic_agents/connectors/mcp/schema_transformer.py

@Eigenwise Eigenwise left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked 6dbfbe4d22838c5e0126014a5676297f7e88cf41. The earlier string/null and integer/string intersections are repaired, with validation and emitted-schema regressions. Normal CI passed 421 tests with 3 MiniMax skips; formatting and lint passed.

One scalar-choice issue remains at schema_transformer.py:41-55: for type: ["boolean", "integer"], enum: [true], input 1 passes the type guard and Literal[True] converts it to True. Conversely, enum: [1] accepts True and returns 1. The existing Pydantic 2.12.4/core 2.41.5 dependency confirms that literal matching behavior; the complete candidate example is source-derived, not locally executed.

Check JSON scalar choice identity before literal matching, and add boolean/numeric union and untyped enum/const regressions. Preserve ordinary numeric equality such as 1 and 1.0. No broader schema redesign requested.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants