Latest Results
feat(langchain): MCP Apps (SEP-1865) tool visibility in `langchain.mcp`
An MCP App is a tool that returns a user interface instead of text: it carries
a `ui://` resource in its `_meta.ui`, a host renders that in a sandboxed frame
beside the conversation, and the tool's result goes into it. The person moves
a slider and approves rather than reading a table and typing "yes, do that."
That makes a tool's audience part of its definition, and it puts one
obligation on anyone building an agent against such a server: a tool marked
`visibility: ["app"]` belongs to the app and MUST be kept out of the model's
tool list. The app exists so a person decides, and a model that can call the
submit tool can skip the person.
`langchain.mcp.apps` is that, and only that:
async with Client(url, extensions=[MCP_APPS_EXTENSION]) as client:
async with MCPAdapter(client) as adapter:
tools = filter_model_visible_tools(await adapter.list_tools())
Two details are easy to get backwards, and both fail silently rather than
loudly, which is why they belong in a library and not in every host:
ABSENT `visibility` MEANS BOTH AUDIENCES. It is absent on every tool on every
server that has never heard of this extension. Treating absent as "neither"
costs such a server half its tools, with nothing raised.
`_meta` MOVES WHEN A TOOL IS ADAPTED. An MCP `Tool` carries it on `.meta`; the
same tool after `MCPAdapter` keeps it under `metadata["mcp"]["tool"]["_meta"]`.
A host filters after adapting, so reading only the first shape hands the model
every app-only tool on the server. There is a test for exactly that path.
`MCP_APPS_EXTENSION` is what a host advertises during `initialize`. It is inert
against a server that always sends `_meta.ui` and load-bearing against one that
gates on the capability: the `ext-apps` SDK ships `getUiCapability` for that,
and its documented example registers a text-only tool for a client that did not
advertise, leaving a host with working tools and no apps.
Rendering the view, reading the `ui://` resource and proxying a view's own
`tools/call` are the browser-facing half and are not here.
13 tests; 91 pass in `tests/unit_tests/mcp`. ruff, format and mypy clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>josiah/mcp-apps-visibility Latest Branches
0%
cc/multimodal-filter-middleware -17%
ccurme/langchain/handle-invalid-tool-calls 0%
josiah/mcp-apps-visibility © 2026 CodSpeed Technology