Description
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.