Avatar for the langchain-ai user
langchain-ai
langchain
BlogDocsChangelog

Performance History

Latest Results

fix(langchain): guard MCP elicitation calls against a dying session `fastmcp.Client.call_tool` races every session request against the background task that owns the session, so a transport failure raises rather than leaving the caller awaiting a reply that can never arrive. Driving the input-required loop directly skipped that guard, so a connection that broke mid-elicitation hung the tool call instead of failing. `_await_monitored` wraps both legs of the loop in the same protection. FastMCP exposes it only privately, so this reaches for it by name and falls back to a plain await if it moves; the fallback loses the hang protection, not correctness. Also documents why `elicitation='interrupt'` is a choice rather than a default. A client declares up front whether it can be asked questions, and servers only build flows that depend on it once a client says yes, so declaring the capability is a promise — one an agent with no path to a human cannot keep.
sydney-runkle/langchain/simplify-mcp-adapter
8 hours ago
feat(langchain): answer MCP elicitation with a LangGraph interrupt An MCP server can need input before it can finish a tool call — a date, a confirmation, a choice among options. `MCPAdapter(target, elicitation="interrupt")` routes those questions to whoever is already reviewing the agent's work: the call raises a LangGraph `interrupt()` carrying the server's question, and resuming with an answer lets the call finish. ```python adapter = MCPAdapter(server, elicitation="interrupt") agent = create_agent(model, await adapter.get_tools(), checkpointer=checkpointer) paused = await agent.ainvoke({"messages": [...]}, config) [question] = paused["__interrupt__"][0].value["requests"] await agent.ainvoke( Command(resume={"responses": {question["key"]: {"action": "accept", "content": {...}}}}), config, ) ``` The loop is driven directly rather than through FastMCP's elicitation handler, because FastMCP converts anything a handler raises into an MCP error — a `GraphInterrupt` raised there is swallowed, and its payload ends up stringified into a tool error the model reads. Driving `session.call_tool(..., allow_input_required=True)` ourselves means `interrupt()` is called from our own frame, where it propagates normally. Requests are correlated by the keys the server chose, so no interrupt ids are needed on resume. Several questions in one round share a single interrupt and a single answer payload; successive rounds each get their own interrupt, and LangGraph's per-task interrupt index replays earlier answers while the newest round raises. Interrupting unwinds the whole tool call, so resuming re-issues it from its first round. A server that asks before doing work — the shape the protocol is built around — repeats nothing, which the tests pin down by counting how often the tool body actually runs. A server that works first and asks later repeats that work once per round, and the module says so. Kept deliberately narrow: - Opt-in. The default declines elicitation exactly as before, and a client only advertises the capability when the adapter is asked for interrupts. - Elicitation only. Embedded sampling and roots requests raise, since driving this loop by hand bypasses the FastMCP callbacks that would answer them. - Modern servers only. The legacy server-initiated path cannot be answered this way at all, and says so rather than failing obscurely. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sydney-runkle/langchain/simplify-mcp-adapter
9 hours ago
feat(langchain): port MCP tool conversion from `langchain-mcp-adapters` Tool conversion now follows `langchain-mcp-adapters` rather than a parallel implementation, so a tool loaded through `langchain.mcp` reaches a model in the same shape as the same tool loaded through that package, and the conversion rules have one home rather than two. `convert_mcp_tool_to_langchain_tool` is public, under the name it already has in `langchain-mcp-adapters`. It takes an MCP tool and the FastMCP client to call it through, so callers who manage their own client can convert tools without an `MCPAdapter`. What the port changes for callers: - Results become real LangChain content blocks. Text, images, resource links, and embedded text or blob resources map onto `create_text_block`, `create_image_block`, and `create_file_block` instead of raw MCP model dumps. Audio raises `NotImplementedError`, since it has no content block yet. - A tool that runs and reports failure reaches the model as a `ToolMessage` with `status="error"`, carrying the server's own error content, so an agent can correct itself. Transport failures and unconvertible content still propagate, since a model cannot act on them. - Structured content arrives as `MCPToolArtifact`, a `TypedDict` with a `structured_content` key, replacing a nested `{"mcp": {...}}` dict. Typing the conversion against `mcp.types.Tool` and FastMCP's `CallToolResult` also removes a layer of `getattr` probing that was quietly broken. `CallToolResult` is a dataclass with no `model_dump`, so the `isError` branch of the old error helper could never be reached and structured content was only ever picked up through its `data` fallback. Two pieces of adapter-side logic go with it. `_client_target` pre-resolved URL strings to a transport to avoid a filesystem probe inside FastMCP's inference; that probe is upstream's to reorder, and blocking briefly in a constructor is not worth the duplicated inference. Duplicate-name validation is gone too: MCP requires tool names to be unique per server, and FastMCP prefixes them per server for multi-server configs, so a collision means a broken server rather than something the adapter should police. Finally, the adapter's own reference counting is gone. FastMCP clients are already reentrant with their own reference counting, so the adapter simply enters the client, and converted tools do the same when invoked — which is why tools now stay callable after the adapter's context exits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sydney-runkle/langchain/simplify-mcp-adapter
10 hours ago
chore(langchain): bump vcrpy test dependency minimum to >=8.2.0
mdrxy/langchain/bump-vcrpy-min
12 hours ago

Latest Branches

CodSpeed Performance Gauge
0%
feat(langchain): `langchain.mcp` namespace, `MCPAdapter`#39939
8 hours ago
9765100
sydney-runkle/langchain/simplify-mcp-adapter
CodSpeed Performance Gauge
0%
12 hours ago
a6c6194
mdrxy/langchain/bump-vcrpy-min
CodSpeed Performance Gauge
0%
feat(langchain): langchain.mcp namespace, `MCPAdapter`#39922
1 day ago
7967693
hunter/langchain/new-mcp-adapteres
© 2026 CodSpeed Technology
Home Terms Privacy Docs