Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Client drops `_meta` from `input_required` results when `allowInputRequired: true` (2026-07-28)

Open Beginner friendly
#2,861 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
90/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
api

Research direction

Read decodeResult in core-internal/src/wire/rev2026-07-28/codec.ts and manualInputRequiredValue in core-internal/src/shared/inputRequiredEngine.ts, starting with the input_required branches. Preserve the server's result-level _meta through both transformations, then verify the provided real-HTTP reproduction returns the metadata from client.callTool.

Written by the indexing model from the issue text.

Description

v2
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:

  1. 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 })
    };
    
  2. 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/[email protected], 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
Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
5d 16h
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from modelcontextprotocol/typescript-sdk

All issues in modelcontextprotocol/typescript-sdk

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.