Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Human in the Loop MCP approval fails #131

Open
@bmz1

Description

@bmz1

Please read this first

  • Have you read the docs? Agents SDK docs
  • Have you searched for related issues? Others may have faced similar issues. ✅

Describe the bug

There is a bug in the serialization logic for RunState that causes data loss for MCP approval items when an agent run is interrupted and resumed. Specifically, the Zod schema for lastProcessedResponse.mcpApprovalRequests is incomplete, causing essential properties like id and providerData to be stripped from the rawItem during serialization.
This leads to a corrupted state upon deserialization, where subsequent logic that relies on these properties fails, making it impossible to correctly handle MCP tool approvals across agent turns.

This results to an 400 The following MCP approval requests do not have an approval: mcpr_... error.

This filter returns an empty array, because providerData is not there.

Solution:
Add id and providerData to rawItem

Debug information

  • Agents SDK version: (e.g. v0.0.8)
  • Runtime environment (e.g. Node.js 22.16.0)

Repro steps

export const agent = new Agent({
  name: "Assistant",
  model: "gpt-4.1-2025-04-14",
  instructions: "You are a helpful assistant.",
  tools: [
    hostedMcpTool({
      serverLabel: "deepwiki",
      serverUrl: "https://mcp.deepwiki.com/mcp",
      requireApproval: "always",
    }),
  ],
});

// Serialization:
let result = await run(agent, [
    { role: "system", content: systemContent },
    { role: "user", content: prompt },
  ]);

  const hasInterruptions = result.interruptions?.length > 0;

  if (hasInterruptions) {
    const uuid = crypto.randomUUID();
    const statePath = path.join("./agent_states", `${uuid}.json`);
    await fs.mkdir(path.dirname(statePath), { recursive: true });
    await fs.writeFile(statePath, JSON.stringify(result.state, null, 2), "utf-8");
}

 // Deserealization:
    const stored = await fs.readFile(statePath, "utf-8");

    const state = await RunState.fromString(agent, stored); // rawItem providerData is no longer there
    const interruptions = state.getInterruptions();

    for (const interruption of interruptions) {
      if (approve) {
        console.log("Approving interruption:", interruption);
        state.approve(interruption, { alwaysApprove: true });
      } else {
        state.reject(interruption);
      }
    }

   let result = await run(agent, state); // error

Expected behavior

No approval error.

I'm happy to open a PR, if it's verified by your side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions