Skip to content
7 changes: 7 additions & 0 deletions .changeset/standard-schema-elicitation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@modelcontextprotocol/core': minor
'@modelcontextprotocol/server': minor
---

Check failure on line 4 in .changeset/standard-schema-elicitation.md

View check run for this annotation

Claude / Claude Code Review

Changeset attributes change to @modelcontextprotocol/core instead of core-internal/client

The changeset bumps `@modelcontextprotocol/core`, but this PR does not touch `packages/core` at all — the protocol changes (new `ElicitInputFormParams`/`ElicitInputResult` types, widened `ServerContext.mcpReq.elicitInput`) live in `packages/core-internal` plus `packages/server`, and `@modelcontextprotocol/client` re-exports the changed public barrel so its bundled types change too. As written, `core` gets a no-op minor release while `core-internal` and `client` are not versioned; the front-matte
Comment on lines +1 to +4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 The changeset bumps @modelcontextprotocol/core, but this PR does not touch packages/core at all — the protocol changes (new ElicitInputFormParams/ElicitInputResult types, widened ServerContext.mcpReq.elicitInput) live in packages/core-internal plus packages/server, and @modelcontextprotocol/client re-exports the changed public barrel so its bundled types change too. As written, core gets a no-op minor release while core-internal and client are not versioned; the front-matter should be '@modelcontextprotocol/core-internal': minor, '@modelcontextprotocol/server': minor, and '@modelcontextprotocol/client': minor, with core removed.

Extended reasoning...

What the bug is. .changeset/standard-schema-elicitation.md declares minor bumps for '@modelcontextprotocol/core' and '@modelcontextprotocol/server'. But this PR's library changes live entirely in packages/core-internal (src/shared/protocol.ts adds ElicitInputFormParams/ElicitInputResult and widens ServerContext.mcpReq.elicitInput into an overload set; src/exports/public/index.ts exports the new types) and packages/server (server.ts overloads, the new elicitation.ts module). Nothing under packages/core is touched.

Why core is the wrong package. packages/core is the public schemas-only package — its barrel re-exports only the *Schema Zod constants (spec + OAuth/OpenID) bundled from core-internal/schemas and core-internal/auth. This PR adds TypeScript types and runtime conversion logic, not new *Schema constants, so @modelcontextprotocol/core's published surface is byte-for-byte unchanged. Bumping it produces a pointless minor release with a misleading changelog entry (the changeset-bot table on this PR confirms core: Minor is what would be released).

Why core-internal and client should be listed instead. Repo convention is consistent: the other pending changesets that touch core-internal/src/shared/protocol.ts (e.g. custom-methods-minimal.md, wraphandler-hook.md, add-sdk-http-error.md, support-standard-json-schema.md) all attribute the change to '@modelcontextprotocol/core-internal' plus the consuming public packages (client and/or server); the only changeset that names '@modelcontextprotocol/core' is add-core-public-package.md, which created that package. core-internal is private but is versioned via changesets (it appears in pre.json initialVersions and in ~30 existing changesets), so omitting it breaks the dependency-cascade bookkeeping. Additionally, both packages/client/src/index.ts and packages/server/src/index.ts re-export @modelcontextprotocol/core-internal/public, and that barrel now gains ElicitInputFormParams/ElicitInputResult plus the modified ServerContext — so the client package's published type surface changes too, yet client gets no bump from this changeset (and with core-internal omitted, the updateInternalDependencies cascade can't pick it up either).

Why nothing catches it. The changeset-bot only checks that a changeset exists; it does not verify that the named packages match the touched paths. The earlier claude[bot] comment that asked for a changeset itself suggested "@modelcontextprotocol/core and /server", which referred to the pre-rename path layout and likely propagated the wrong package name into this changeset.

Step-by-step proof.

  1. git diff for this PR shows changes under packages/core-internal/, packages/server/, docs, and examples — zero files under packages/core/.
  2. The changeset front-matter lists '@modelcontextprotocol/core': minor and '@modelcontextprotocol/server': minor.
  3. On the next changeset version/release, @modelcontextprotocol/core is published with a bumped version and a changelog entry describing Standard Schema elicitation — a feature that does not exist in that package's contents.
  4. Meanwhile @modelcontextprotocol/client (whose d.ts surface now includes the new exported types and the changed ServerContext.mcpReq.elicitInput overloads via the re-exported public barrel) and @modelcontextprotocol/core-internal (where the change actually lives) get no version bump, so the change is unrecorded for the packages that actually changed.

How to fix. Replace the front-matter with:

---
'@modelcontextprotocol/core-internal': minor
'@modelcontextprotocol/server': minor
'@modelcontextprotocol/client': minor
---

(client could arguably be patch, but minor matches how sibling changesets like add-sdk-http-error.md treat new public type exports.) The changeset body text can stay as-is.


Allow form elicitation requests to accept Standard Schema values such as Zod objects for `requestedSchema`. The server converts these schemas to MCP's restricted elicitation JSON Schema before sending and parses accepted content with the original schema before returning typed
results. Zod string formats that map to MCP's supported `email`, `uri`, `date`, or `date-time` formats are accepted; arbitrary regex patterns remain rejected because form elicitation does not carry JSON Schema `pattern`.
8 changes: 8 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,18 @@ server.setRequestHandler('tools/call', async (request, ctx) => {
requestedSchema: { type: 'object', properties: { name: { type: 'string' } } }
});

// Or pass a Standard Schema such as a Zod object for typed content.
const typedElicitResult = await ctx.mcpReq.elicitInput({
message: 'Please provide details',
requestedSchema: z.object({ name: z.string().meta({ title: 'Name' }) })
});

return { content: [{ type: 'text', text: 'done' }] };
});
```

Standard Schemas passed to `elicitInput` are converted to MCP's restricted form-elicitation JSON Schema before being sent. They must describe a flat object with primitive properties; accepted responses are parsed with the original schema before `result.content` is returned. With Zod v4, use `.meta({ title: 'Field Label' })` for short form-field labels. Zod string helpers that emit the supported `email`, `uri`, `date`, or `date-time` formats are accepted; arbitrary `.regex()` patterns are rejected because form elicitation does not carry JSON Schema `pattern`.

These replace the pattern of calling `server.sendLoggingMessage()`, `server.createMessage()`, and `server.elicitInput()` from within handlers.

### Error hierarchy refactoring
Expand Down
22 changes: 9 additions & 13 deletions docs/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,11 @@ Elicitation lets a tool handler request direct input from the user — form fiel
> [!IMPORTANT]
> Sensitive information must not be collected via form elicitation; always use URL elicitation or out-of-band flows for secrets.

For form elicitation, pass either the restricted JSON Schema shape used by the MCP wire protocol or a Standard Schema such as a Zod object. Standard Schemas are converted to the restricted elicitation JSON Schema before being sent, so they must describe a flat object with
primitive properties (`string`, `number`, `integer`, `boolean`, or string enum fields). When the user accepts the form, `result.content` is parsed with the original Standard Schema and is typed as that schema's output. With Zod v4, use `.meta({ title: 'Field Label' })` for short
form-field labels; `.describe()` maps to JSON Schema `description`, not `title`. Zod string helpers that emit the supported `email`, `uri`, `date`, or `date-time` formats are accepted; arbitrary `.regex()` patterns are rejected because form elicitation does not carry JSON Schema
`pattern`.

Call `ctx.mcpReq.elicitInput(params)` (from {@linkcode @modelcontextprotocol/server!index.ServerContext | ServerContext}) inside a tool handler:

```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_elicitation"
Expand All @@ -510,19 +515,10 @@ server.registerTool(
const result = await ctx.mcpReq.elicitInput({
mode: 'form',
message: 'Please share your feedback:',
requestedSchema: {
type: 'object',
properties: {
rating: {
type: 'number',
title: 'Rating (1\u20135)',
minimum: 1,
maximum: 5
},
comment: { type: 'string', title: 'Comment' }
},
required: ['rating']
}
requestedSchema: z.object({
rating: z.number().min(1).max(5).meta({ title: 'Rating (1-5)' }),
comment: z.string().optional().meta({ title: 'Comment' })
})
});
if (result.action === 'accept') {
return {
Expand Down
47 changes: 10 additions & 37 deletions examples/server/src/elicitationFormExample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
import { isInitializeRequest, McpServer } from '@modelcontextprotocol/server';
import type { Request, Response } from 'express';
import * as z from 'zod/v4';

// Create a fresh MCP server per client connection to avoid shared state between clients.
// The validator supports format validation (email, date, etc.) if ajv-formats is installed.
Expand All @@ -38,51 +39,23 @@
},
async () => {
try {
const registrationSchema = z.object({
username: z.string().min(3).max(20).meta({ title: 'Username', description: 'Your desired username (3-20 characters)' }),
email: z.string().email().meta({ title: 'Email', description: 'Your email address' }),
password: z.string().min(8).meta({ title: 'Password', description: 'Your password (min 8 characters)' }),
newsletter: z.boolean().default(false).meta({ title: 'Newsletter', description: 'Subscribe to newsletter?' })
});

Check warning on line 47 in examples/server/src/elicitationFormExample.ts

View check run for this annotation

Claude / Claude Code Review

New example/test use deprecated z.string().email() instead of z.email()

The new register_user example (examples/server/src/elicitationFormExample.ts:44) and the new accept-path test in jsonSchemaValidatorOverride.test.ts:138 use z.string().email(), but in Zod v4 the ZodString .email() method is @deprecated in favor of the top-level z.email() helper (which the same test file already uses elsewhere). Since this is brand-new showcase code for the Zod-based elicitation path, switch to z.email().meta({...}) — runtime behavior is identical.
Comment on lines +42 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 The new register_user example (examples/server/src/elicitationFormExample.ts:44) and the new accept-path test in jsonSchemaValidatorOverride.test.ts:138 use z.string().email(), but in Zod v4 the ZodString .email() method is @deprecated in favor of the top-level z.email() helper (which the same test file already uses elsewhere). Since this is brand-new showcase code for the Zod-based elicitation path, switch to z.email().meta({...}) — runtime behavior is identical.

Extended reasoning...

What the issue is. This PR rewrites the register_user example and adds a new accept-path test, both using email: z.string().email(). In the workspace's Zod v4 (catalog ^4.2.0, currently resolving to 4.3.x), ZodString.prototype.email() is explicitly marked /** @deprecated Use z.email() instead. */ in zod/v4/classic/schemas.d.ts (the same applies to .url(), .uuid(), etc.). Zod's v4 docs steer users to the top-level z.email() helper, and the deprecated string-method form is slated for removal in a future major.

Where it appears. Both occurrences are newly introduced by this PR — they are the only usages of z.string().email() in the repo, so this is not following an existing convention:

  • examples/server/src/elicitationFormExample.ts:44email: z.string().email().meta({ title: 'Email', ... }) in the rewritten register_user registration schema.
  • packages/server/test/server/jsonSchemaValidatorOverride.test.ts:138 — the new "accepts a Standard Schema requestedSchema" test.

Notably, the same test file already uses the modern form a little further down: the rejection test uses z.email({ pattern: /@corp\.com$/ }). So the PR is internally inconsistent about which API it models.

Why it matters. These two files are the canonical showcase for the new Standard Schema elicitation path — the example is what users will copy. Teaching the deprecated API surfaces editor strikethrough/lint deprecation warnings for anyone following the example, and would break when Zod removes the method. Since the SDK's docs prose added by this PR (docs/server.md, docs/migration.md) already recommends the Zod v4 idioms (.meta({ title })), the example should model the current API as well.

Why nothing breaks at runtime. Both z.string().email() and z.email() emit identical JSON Schema through standardSchemaToJsonSchemaformat: 'email' plus Zod's canonical email regex as pattern — and that canonical pattern is exactly what the new redundant-pattern exemption in isRedundantFormatPattern (packages/server/src/server/elicitation.ts) accepts. So the wire schema, the strip check, and the accept-path validation behave the same either way. This is purely an API-currency issue, not a functional bug.

Step-by-step. (1) A user copies the register_user example into their project. (2) Their editor shows email() struck through with "Use z.email() instead", and lint rules like @typescript-eslint/no-deprecated flag it. (3) They either ignore the warning (and inherit a removal-pending API) or have to figure out the replacement themselves — neither of which a flagship example should require. The same applies to anyone reading the test as reference usage.

How to fix. One-token change in both places: email: z.email().meta({ title: 'Email', description: 'Your email address' }) in the example, and email: z.email().meta({ title: 'Email', description: 'Email address' }) in the test. The expected wire schema and assertions in the test remain valid unchanged.


// Request user information through form elicitation
const result = await mcpServer.server.elicitInput({
mode: 'form',
message: 'Please provide your registration information:',
requestedSchema: {
type: 'object',
properties: {
username: {
type: 'string',
title: 'Username',
description: 'Your desired username (3-20 characters)',
minLength: 3,
maxLength: 20
},
email: {
type: 'string',
title: 'Email',
description: 'Your email address',
format: 'email'
},
password: {
type: 'string',
title: 'Password',
description: 'Your password (min 8 characters)',
minLength: 8
},
newsletter: {
type: 'boolean',
title: 'Newsletter',
description: 'Subscribe to newsletter?',
default: false
}
},
required: ['username', 'email', 'password']
}
requestedSchema: registrationSchema
Comment thread
claude[bot] marked this conversation as resolved.
});

// Handle the different possible actions
if (result.action === 'accept' && result.content) {
const { username, email, newsletter } = result.content as {
username: string;
email: string;
password: string;
newsletter?: boolean;
};
const { username, email, newsletter } = result.content;

return {
content: [
Expand Down
17 changes: 4 additions & 13 deletions examples/server/src/serverGuide.examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,19 +418,10 @@ function registerTool_elicitation(server: McpServer) {
const result = await ctx.mcpReq.elicitInput({
mode: 'form',
message: 'Please share your feedback:',
requestedSchema: {
type: 'object',
properties: {
rating: {
type: 'number',
title: 'Rating (1\u20135)',
minimum: 1,
maximum: 5
},
comment: { type: 'string', title: 'Comment' }
},
required: ['rating']
}
requestedSchema: z.object({
rating: z.number().min(1).max(5).meta({ title: 'Rating (1-5)' }),
comment: z.string().optional().meta({ title: 'Comment' })
})
Comment thread
claude[bot] marked this conversation as resolved.
});
if (result.action === 'accept') {
return {
Expand Down
12 changes: 6 additions & 6 deletions packages/codemod/src/generated/versions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// AUTO-GENERATED — do not edit. Run `pnpm run generate:versions` to regenerate.
export const V2_PACKAGE_VERSIONS: Record<string, string> = {
'@modelcontextprotocol/client': '^2.0.0-alpha.2',
'@modelcontextprotocol/server': '^2.0.0-alpha.2',
'@modelcontextprotocol/node': '^2.0.0-alpha.2',
'@modelcontextprotocol/express': '^2.0.0-alpha.2',
'@modelcontextprotocol/server-legacy': '^2.0.0-alpha.2',
'@modelcontextprotocol/core': '^2.0.0-alpha.0'
'@modelcontextprotocol/client': '^2.0.0-alpha.3',
'@modelcontextprotocol/server': '^2.0.0-alpha.3',
'@modelcontextprotocol/node': '^2.0.0-alpha.3',
'@modelcontextprotocol/express': '^2.0.0-alpha.3',
'@modelcontextprotocol/server-legacy': '^2.0.0-alpha.3',
'@modelcontextprotocol/core': '^2.0.0-alpha.1'
};
2 changes: 2 additions & 0 deletions packages/core-internal/src/exports/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export { getDisplayName } from '../../shared/metadataUtils';
export type {
BaseContext,
ClientContext,
ElicitInputFormParams,
ElicitInputResult,
NotificationOptions,
ProgressCallback,
ProtocolOptions,
Expand Down
22 changes: 20 additions & 2 deletions packages/core-internal/src/shared/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
ProtocolErrorCode,
SUPPORTED_PROTOCOL_VERSIONS
} from '../types/index';
import type { StandardSchemaV1 } from '../util/standardSchema';
import type { StandardSchemaV1, StandardSchemaWithJSON } from '../util/standardSchema';
import { isStandardSchema, validateStandardSchema } from '../util/standardSchema';
import type { Transport, TransportSendOptions } from './transport';

Expand Down Expand Up @@ -203,6 +203,18 @@ export type BaseContext = {
};
};

export type ElicitInputFormParams<Schema extends StandardSchemaWithJSON = StandardSchemaWithJSON> = Omit<
ElicitRequestFormParams,
'requestedSchema'
> & {
requestedSchema: Schema;
Comment thread
claude[bot] marked this conversation as resolved.
};

export type ElicitInputResult<Schema extends StandardSchemaWithJSON> = Result & {
action: ElicitResult['action'];
content?: StandardSchemaWithJSON.InferOutput<Schema>;
};
Comment thread
claude[bot] marked this conversation as resolved.

/**
* Context provided to server-side request handlers, extending {@linkcode BaseContext} with server-specific fields.
*/
Expand All @@ -221,7 +233,13 @@ export type ServerContext = BaseContext & {
/**
* Send an elicitation request to the client, requesting user input.
*/
elicitInput: (params: ElicitRequestFormParams | ElicitRequestURLParams, options?: RequestOptions) => Promise<ElicitResult>;
elicitInput: {
<Schema extends StandardSchemaWithJSON>(
params: ElicitInputFormParams<Schema>,
options?: RequestOptions
): Promise<ElicitInputResult<Schema>>;
(params: ElicitRequestFormParams | ElicitRequestURLParams, options?: RequestOptions): Promise<ElicitResult>;
};

/**
* Request LLM sampling from the client.
Expand Down
142 changes: 142 additions & 0 deletions packages/server/src/server/elicitation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import type { ElicitInputFormParams, ElicitRequestFormParams, StandardSchemaWithJSON } from '@modelcontextprotocol/core-internal';
import {
ElicitRequestFormParamsSchema,
parseSchema,
ProtocolError,
ProtocolErrorCode,
standardSchemaToJsonSchema
} from '@modelcontextprotocol/core-internal';

export type NormalizedElicitInputFormParams = {
params: ElicitRequestFormParams;
standardSchema?: StandardSchemaWithJSON;
};

function isJsonObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}

const ZOD_ISO_DATE_PATTERN = String.raw`(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))`;
const ZOD_ISO_TIME_PREFIX = String.raw`(?:[01]\d|2[0-3]):[0-5]\d`;
const ZOD_ISO_OFFSET_PATTERN = String.raw`([+-](?:[01]\d|2[0-3]):[0-5]\d)`;

const ZOD_REDUNDANT_FORMAT_PATTERNS: ReadonlyMap<string, ReadonlySet<string>> = new Map([
['email', new Set([String.raw`^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$`])],
[
'date',
new Set([
String.raw`^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))$`
])
]
]);

const ZOD_DATETIME_ZONE_SUFFIXES = [
String.raw`(?:Z)`,
String.raw`(?:Z|)`,
String.raw`(?:Z|${ZOD_ISO_OFFSET_PATTERN})`,
String.raw`(?:Z||${ZOD_ISO_OFFSET_PATTERN})`
] as const;

function escapeRegExpLiteral(value: string): string {
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, match => `\\${match}`);
}

const ZOD_PRECISION_TIME_PATTERN = new RegExp(String.raw`^${escapeRegExpLiteral(String.raw`${ZOD_ISO_TIME_PREFIX}:[0-5]\d\.\d{`)}\d+\}$`);

function isZodIsoDatetimePattern(pattern: string): boolean {
const prefix = `^${ZOD_ISO_DATE_PATTERN}T(?:`;
if (!pattern.startsWith(prefix) || !pattern.endsWith(')$')) {
return false;
}

const innerPattern = pattern.slice(prefix.length, -2);
const zoneSuffix = ZOD_DATETIME_ZONE_SUFFIXES.find(suffix => innerPattern.endsWith(suffix));
if (!zoneSuffix) {
return false;
}

const timePattern = innerPattern.slice(0, -zoneSuffix.length);
return (
timePattern === String.raw`${ZOD_ISO_TIME_PREFIX}` ||
timePattern === String.raw`${ZOD_ISO_TIME_PREFIX}:[0-5]\d` ||
timePattern === String.raw`${ZOD_ISO_TIME_PREFIX}(?::[0-5]\d(?:\.\d+)?)?` ||
ZOD_PRECISION_TIME_PATTERN.test(timePattern)
);
}

function isRedundantFormatPattern(original: Record<string, unknown>, parsed: Record<string, unknown>, key: string): boolean {
if (
key !== 'pattern' ||
typeof original.pattern !== 'string' ||
parsed.type !== 'string' ||
typeof parsed.format !== 'string' ||
original.format !== parsed.format
) {
return false;
}

if (parsed.format === 'date-time') {
return isZodIsoDatetimePattern(original.pattern);
}

return ZOD_REDUNDANT_FORMAT_PATTERNS.get(parsed.format)?.has(original.pattern) === true;
}
Comment thread
mattzcarey marked this conversation as resolved.

function findStrippedJsonSchemaPaths(original: unknown, parsed: unknown, path = ''): string[] {
if (Array.isArray(original) && Array.isArray(parsed)) {
return original.flatMap((item, index) => findStrippedJsonSchemaPaths(item, parsed[index], `${path}[${index}]`));
}

if (!isJsonObject(original) || !isJsonObject(parsed)) {
return [];
}

return Object.entries(original).flatMap(([key, value]) => {
const childPath = path ? `${path}.${key}` : key;
if (!Object.prototype.hasOwnProperty.call(parsed, key)) {
if (isRedundantFormatPattern(original, parsed, key)) {
return [];
}
return [childPath];
}
return findStrippedJsonSchemaPaths(value, parsed[key], childPath);
});
}

function isElicitInputSchema(
schema: ElicitRequestFormParams['requestedSchema'] | StandardSchemaWithJSON
): schema is StandardSchemaWithJSON {
return typeof schema === 'object' && schema !== null && '~standard' in schema;
}

export function normalizeElicitInputFormParams(
params: ElicitRequestFormParams | ElicitInputFormParams<StandardSchemaWithJSON>
): NormalizedElicitInputFormParams {
const formParams =
params.mode === 'form' ? (params as ElicitRequestFormParams) : { ...(params as ElicitRequestFormParams), mode: 'form' as const };

if (isElicitInputSchema(formParams.requestedSchema)) {
const standardSchema = formParams.requestedSchema;
const normalizedParams = {
...formParams,
requestedSchema: standardSchemaToJsonSchema(standardSchema, 'input')
};
const parsedParams = parseSchema(ElicitRequestFormParamsSchema, normalizedParams);
if (!parsedParams.success) {
throw new ProtocolError(
ProtocolErrorCode.InvalidParams,
`Elicitation requestedSchema only supports flat primitive properties (string, number, integer, boolean, and string enums): ${parsedParams.error.message}`
);
}
const strippedSchemaPaths = findStrippedJsonSchemaPaths(normalizedParams.requestedSchema, parsedParams.data.requestedSchema);
if (strippedSchemaPaths.length > 0) {
throw new ProtocolError(
ProtocolErrorCode.InvalidParams,
`Elicitation requestedSchema contains unsupported JSON Schema keyword(s) after Standard Schema conversion: ${strippedSchemaPaths.join(', ')}`
);
}
return { params: parsedParams.data, standardSchema };
}

return { params: formParams };
}
Loading
Loading