Describe the bug
With protocol revision 2026-07-28, a client that calls a tool with { allowInputRequired: true } gets an InputRequiredResult that has no _meta, even when the server's result includes _meta.
InputRequiredResult is a Result, so _meta is valid on it, and the SDK's own InputRequiredResultSchema (wireResult(...)) includes _meta. But the manual input_required path rebuilds the result from only inputRequests and requestState, so the field is lost. A server cannot send result-level metadata (for example display hints for the inputRequests) to a client that fulfils rounds by itself.
Where it happens
The field is dropped in two places:
core-internal/src/wire/rev2026-07-28/codec.ts, in decodeResult, in the input_required branch:
return {
kind: 'input_required',
inputRequests,
...(typeof requestState === 'string' && { requestState })
};
core-internal/src/shared/inputRequiredEngine.ts, in manualInputRequiredValue:
return {
resultType: 'input_required',
inputRequests: decoded.inputRequests,
...(decoded.requestState !== undefined && { requestState: decoded.requestState })
};
The transport's JSONRPCMessageSchema.parse keeps result._meta. The field is lost only in these two steps.
To reproduce
Server: return this from a tools/call handler:
{
"resultType": "input_required",
"requestState": "state-1",
"inputRequests": {
"approval": {
"method": "elicitation/create",
"params": { "mode": "form", "message": "Allow?", "requestedSchema": { "type": "object", "properties": {} } }
}
},
"_meta": { "example/hint": { "tools": ["a"] } }
}
Client:
const client = new Client(
{ name: "repro", version: "0.0.0" },
{
capabilities: { elicitation: { form: {} } },
supportedProtocolVersions: ["2026-07-28"],
versionNegotiation: { mode: { pin: "2026-07-28" } },
inputRequired: { autoFulfill: false },
},
);
await client.connect(new StreamableHTTPClientTransport(new URL(url)));
const result = await client.callTool({ name: "tool", arguments: {} }, { allowInputRequired: true });
console.log(result._meta); // undefined
Expected behavior
result._meta equals the _meta that the server sent, the same as for a complete result.
Actual behavior
result._meta is undefined.
Suggested fix
Carry _meta through both steps:
// codec.ts, input_required branch
const meta = raw['_meta'];
return {
kind: 'input_required',
inputRequests,
...(typeof requestState === 'string' && { requestState }),
...(isPlainObject(meta) && { _meta: meta })
};
// inputRequiredEngine.ts
return {
resultType: 'input_required',
inputRequests: decoded.inputRequests as InputRequiredResult['inputRequests'],
...(decoded.requestState !== undefined && { requestState: decoded.requestState }),
...(decoded._meta !== undefined && { _meta: decoded._meta })
};
We use this change as a local pnpm patch on @modelcontextprotocol/client@2.0.0, and a real-HTTP test confirms that _meta reaches the caller.
Versions
@modelcontextprotocol/client 2.0.0 (the same code is in 2.1.0)
- Protocol revision
2026-07-28
- Node.js 22.19.0
Describe the bug
With protocol revision
2026-07-28, a client that calls a tool with{ allowInputRequired: true }gets anInputRequiredResultthat has no_meta, even when the server's result includes_meta.InputRequiredResultis aResult, so_metais valid on it, and the SDK's ownInputRequiredResultSchema(wireResult(...)) includes_meta. But the manualinput_requiredpath rebuilds the result from onlyinputRequestsandrequestState, so the field is lost. A server cannot send result-level metadata (for example display hints for theinputRequests) to a client that fulfils rounds by itself.Where it happens
The field is dropped in two places:
core-internal/src/wire/rev2026-07-28/codec.ts, indecodeResult, in theinput_requiredbranch:core-internal/src/shared/inputRequiredEngine.ts, inmanualInputRequiredValue:The transport's
JSONRPCMessageSchema.parsekeepsresult._meta. The field is lost only in these two steps.To reproduce
Server: return this from a
tools/callhandler:{ "resultType": "input_required", "requestState": "state-1", "inputRequests": { "approval": { "method": "elicitation/create", "params": { "mode": "form", "message": "Allow?", "requestedSchema": { "type": "object", "properties": {} } } } }, "_meta": { "example/hint": { "tools": ["a"] } } }Client:
Expected behavior
result._metaequals the_metathat the server sent, the same as for acompleteresult.Actual behavior
result._metaisundefined.Suggested fix
Carry
_metathrough both steps:We use this change as a local
pnpm patchon@modelcontextprotocol/client@2.0.0, and a real-HTTP test confirms that_metareaches the caller.Versions
@modelcontextprotocol/client2.0.0 (the same code is in 2.1.0)2026-07-28