interrupt, Agent Server asks the MCP client for the answer with elicitation. When the client answers, Agent Server resumes the agent. A person can answer a question, review a tool call, or complete a sign-in flow without leaving the MCP client. To answer interrupts through the Agent Server API instead, see Human-in-the-loop using server API.
Human-in-the-loop over MCP requires
langgraph-api>=0.18.0 and an MCP client that uses protocol revision 2026-07-28 and declares the elicitation capability.Pause and resume a tool call
Each pause is one round trip between the client and Agent Server:- The client calls the tool. Agent Server runs the agent on a new thread.
- The agent calls
interrupt(). The tool call returns"resultType": "input_required", with oneelicitation/createrequest per question ininputRequests, and an opaquerequestState. - The client asks the user. Then it calls the same tool again with the same arguments, the answers in
inputResponsesunder the same keys, and therequestStateit received. - Agent Server resumes the agent. The result is either a new round of questions, with a new
requestState, or the tool result.
greeter agent from Relay elicitation requests asks for a name:
{"greeting":"Hello, Ada!"}.
These examples show the request and response bodies. On 2026-07-28, MCP clients also send the MCP-Protocol-Version: 2026-07-28 header, and Mcp-Method and Mcp-Name headers that match the body. Without the version header, Agent Server treats the request as coming from an older client. A pause then returns the error result described in Support clients without elicitation.
Agent Server applies these rules to every round:
- Several questions: When several interrupts are pending at once, such as from parallel nodes, Agent Server asks all of them in one round.
- Missing answers: When
inputResponseslacks an answer to a question, Agent Server asks the same questions again, with the samerequestState. It ignores answers to questions it did not ask. - Answers in the first call: Answers sent in the first call, without a
requestState, answer the first round of questions. - Repeated answers: Agent Server resumes the agent once, even when the client sends the same answers more than once.
- Invalid answers: An answer that does not fit its question fails with JSON-RPC error
-32602and HTTP status 400. When the answer came with arequestState, the round stays open, so the client can answer it again. An invalid answer in a first call, without arequestState, deletes that call’s thread, so the client calls the tool again from the start. - Invalid state: A modified
requestState, or one sent with another tool name or other arguments, fails with JSON-RPC error-32602(Invalid or expired requestState) and HTTP status 400. - Runtime context: A request can carry a
contextobject next toarguments, which becomes the agent’s runtime context. When a request answers a round, the resumed run gets that request’scontext. - Lifetime: When a request without a
requestStatefinishes the tool call, Agent Server deletes the thread. When a request with arequestStatefinishes it, Agent Server keeps the thread for 10 minutes. A client that resends its last answers in that time gets the same result. A call that stays paused expires 24 hours after its latest round of questions. A shorterdefault_ttlin the thread TTL configuration shortens both times.
Ask a text question
When the interrupt value is a string, Agent Server asks it as a form with one text field:inputRequests:
response field, such as {"action": "accept", "content": {"response": "eu-west-1"}}, and the agent resumes with the string eu-west-1. A decline or cancel answer ends the tool call with an error result: The request for input was declined. or The request for input was cancelled.
Agent Server derives the key from the question, so the key stays the same when a client sends the call again from the start. When two pending interrupts ask the same text question, one answer resumes both.
Ask for typed input
To ask for structured input, pass aresponse_schema to interrupt(). Response schemas require langgraph>=1.2.12. Agent Server turns the schema into the form and checks each answer against it. When the schema is a type, such as a Pydantic model, LangGraph also validates the answer before the agent resumes:
{"region": "eu-west-1", "replicas": 3} resumes the agent, and the tool result is {"region":"eu-west-1","replicas":3}. An answer outside the schema, such as "replicas": 20, fails with error -32602 (Form content does not match requestedSchema), and the client can answer again. With a Pydantic model, interrupt() returns an instance of the model.
When the schema does not describe an object, such as int, the form has one response field, and the agent resumes with its value. When the interrupt value is not a string, the question shows it as JSON. Agent Server cannot ask an interrupt whose value is not a string and that has no response_schema.
Agent Server accepts form schemas that follow the MCP rules for elicitation:
- Fields: The schema is a flat object. Each property is a string, number, integer, boolean, single-choice enum, or multi-select array of string choices.
- String formats: Strings can use the
email,uri,date, ordate-timeformat. - Field keywords: Each field can carry
title,description, anddefault, plusminLength,maxLength,minimum,maximum,minItems, andmaxItemswhere they apply. Agent Server cannot ask a question whose fields use other keywords, such aspattern,multipleOf, or theexclusiveMinimumfrom a Pydanticgt. - Size: A form has 1 to 100 fields, and its schema is at most 1 MiB.
- Pydantic schemas: Agent Server resolves local
$defsreferences, turns optional fields into plain fields, and drops titles and descriptions at the root.
This tool needs input that can't be asked over MCP.
Do not ask for passwords, API keys, access tokens, or payment credentials in a form. The MCP specification forbids it. Send the user to a page instead, as described in Send the user to a URL.
Relay elicitation requests
An interrupt value whosetype is mcp_elicitation carries MCP elicitation requests. Agent Server checks each request against the rules for forms and URLs, then passes it to the client. MCPAdapter and the LangChain JavaScript MCP adapter raise this interrupt when a tool on another MCP server asks for input. An agent that uses such a tool then relays the question to its own MCP client. An agent can also raise the interrupt directly, as this greeter agent does:
requests has these fields:
key: Identifies the request. The answer comes back under this key.message: The question to show the user.mode:formorurl.requested_schema: The form schema, whenmodeisform.url: The page to send the user to, whenmodeisurl.
requests can also be an object that maps each key to its request, with the field names that MCP uses, such as requestedSchema. In that shape, a request without a mode is a form. The LangChain JavaScript MCP adapter uses this shape. Agent Server ignores other keys in the interrupt value, such as the tool_name that MCPAdapter adds.
The agent resumes with {"responses": {key: answer}}, one answer per request. Each answer has an action of accept, decline, or cancel, and an accept answer to a form carries its content. Agent Server passes declined and canceled answers to the agent, so the agent decides what happens next. In the example, a declined question returns Hello, stranger!.
When only one interrupt is pending, the client sees the agent’s own keys. When several are pending, Agent Server prefixes each key with a digest of its interrupt, such as <digest>.1/user_name. Agent Server then asks two tool calls that use the same key as separate questions. The agent still receives its answers under its own keys.
Send the user to a URL
Use"mode": "url" to send the user to a page, such as an OAuth consent screen, so that sensitive data never passes through the MCP client:
accept answer has no content. It confirms that the user finished the flow on that page.
Agent Server asks a URL question only when the URL meets these rules:
- Scheme: HTTPS, or HTTP on
localhost,127.0.0.1, or[::1]. - Host: The URL names a host.
- Credentials: The URL contains no user name or password.
- Length: The URL is at most 4,096 characters.
url mode of the elicitation capability. For a client that declares only form, the call fails with error -32021:
url mode, the call fails the same way. Agent Server then keeps the paused call for 10 minutes instead of 24 hours. In that time, the client can declare url and resend the same answers and requestState to get the URL question.
Review tool calls
When an agent built withHumanInTheLoopMiddleware pauses for review, Agent Server asks one question per tool call. Both interrupt modes work, in Python and in JavaScript: batched mode, the default, and per-call mode. Per-call mode requires langchain>=1.4.6 with interrupt_mode="per_call" in Python. In JavaScript, it requires the langchain package 1.5.18 or later, with interruptMode: "per_call".
The question’s message is the middleware’s description of the call, or Run <tool>? when the call has none. Its form has these fields:
decision: Required. One of the decisions that the call allows, each with a title.message: The reason for a rejection, or the answer to send in place of the tool. Present when the call allowsrejectorrespond.args: The arguments to run the tool with, as a JSON object in a string, prefilled with the arguments that the model chose. Present when the call allowsedit.
send_email with to set to ada@example.com and subject set to Launch, the client receives this question:
An edit can change the arguments, not the tool. A
cancel answer, or a decline answer to a call that does not allow reject, ends the tool call with an error result.
These answers fail with error -32602, and the client can answer again:
- Arguments that are not a JSON object.
- A
responddecision without a message. - A decision that the call does not allow.
response_schema lists the decisions that the call allows and, when the tool declares them, its argument types. Agent Server checks each decision against that schema before the agent resumes. An edit that breaks the tool’s argument types fails with error -32602, such as The decision does not fit the tool: "subject" is a required property, and no tool runs. Agent Server never fetches a reference in that schema. When the schema refers to a document outside itself, Agent Server asks the question without the check.
Each tool call gets its own question, even when two calls have the same tool and the same arguments. When a call’s arguments are too large to prefill in a form, Agent Server asks the question without the edit choice. It then cannot ask about a call that allows only edit.
For more information on review decisions, see Human-in-the-loop.
Support clients without elicitation
Clients that cannot elicit get an explicit error when a tool pauses:- Clients on
2026-07-28without theelicitationcapability: The call fails with JSON-RPC error-32021(This tool asks for human input and needs form elicitation.) and HTTP status 400.data.requiredCapabilitieslists every mode that the round needs, such as{"elicitation": {"form": {}}}. A client that declareselicitationwith no modes supportsform. - Clients on
2025-11-25or earlier: The tool returns an error result. Its first text block isThis tool paused to ask for human input, and this client can't answer it., and the second lists the pending interrupts as JSON. - Calls that cannot keep a thread: The tool returns an error result whose first text block is
This tool paused to ask for human input, and this call can't be resumed.This happens when the deployment disables threads. It also happens when your custom auth handlers do not let the caller create or update the call’s thread.
interrupt_before or interrupt_after. For a client that can elicit, the tool call ends with an error result. Other clients receive the graph’s state at the breakpoint as a normal tool result.
Answer from a LangChain agent
An agent that calls the tool throughMCPAdapter, from langchain[mcp]>=1.4.0, pauses with an mcp_elicitation interrupt and resumes with the user’s answers. In JavaScript, @langchain/mcp-adapters 2.0.0 or later does the same. For the client code, see Elicitation.
After each answer, the adapter calls the tool again from the start, without a requestState. When Agent Server asks an earlier question again, the adapter answers it with the stored answer for the same key. It sends the new requestState of that round. The agent behind the tool reruns up to each question, and the thread of the earlier attempt stays paused until it expires.
This replay works because Agent Server derives each key from its question. If a rerun asks a different question, the key changes and the adapter raises an error. For example, a review question changes when the model behind the tool proposes other arguments. Place questions before expensive work or side effects.
If a rerun asks no question, the tool call finishes without the stored answer, and the adapter raises no error. For example, the model behind the tool can skip the call that the user approved.
Secure paused calls
Agent Server protects paused calls as follows:- Bound state: A
requestStateworks only for the agent, tool name, and arguments of the call that produced it. - Authorization: Agent Server reads the paused thread as the caller, through your custom auth handlers. A
requestStatefrom another user fails with error-32602. - Stored value: The thread stores only a keyed hash of the token in
requestState, so reading the thread metadata does not reveal a usable value.
See also
- MCP endpoint in Agent Server
- Human-in-the-loop using server API
- Interrupts
- Human-in-the-loop
- Elicitation in LangChain MCP tools
Connect these docs to your agent of choice via MCP for real-time answers.

