#8952·langgraph

MCP tools/list: annotations hardcoded identically for every tool, and incorrect for read-only/destructive tools

Author: rhadiarisCreated Sep 17, 2026Updated Sep 17, 2026
Labelsexternal

Summary

The tools/list handler in langgraph-api sets the same annotations object for every MCP tool it exposes, regardless of the underlying assistant's actual behavior. For tools that are genuinely read-only or genuinely destructive, the asserted values are wrong, not just generically unhelpful.

Location

langgraph_api/api/mcp/_handlers.py, handle_tools_list()_get_tool() (lines ~295–306 in 0.7.90). Confirmed unchanged in the latest release as of 2026-09-17, 0.14.1 (51 stable releases later, spanning 2026-03-27 to 2026-09-14) — same function, same lines, byte-identical logic.

Current behavior

python
return {
    "name": normalized_name,
    "title": assistant["name"],
    "description": assistant.get("description") or f"Tool based on the {assistant['name']} assistant",
    "inputSchema": input_schema,
    "annotations": {
        "readOnlyHint": False,
        "destructiveHint": False,
        "idempotentHint": False,
        "openWorldHint": True,
    },
}

This is unconditional — no read from assistant metadata, no per-graph config, nothing derived from input_schema or description.

Reproduction

Deploy any two assistants via langgraph.json (or a Platform-hosted MCP surface) where one is a pure read/status-lookup graph and another performs an irreversible action (e.g. a cancel/delete operation). Call tools/list against the deployment's /mcp endpoint. Both tools come back with identical annotations: readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true — even though one is read-only and the other is destructive.

Impact

Per the MCP spec, ToolAnnotations exist so a client can make consent/UX decisions (auto-approve vs. confirm-before-calling) without an LLM parsing the tool's description prose. With every tool asserting identical, and for some tools incorrect, hints, no annotation-aware MCP client can rely on this field against a LangGraph Platform-hosted deployment. This also blocks meeting connector-directory submission requirements on both Anthropic's Claude Connector Directory and OpenAI's ChatGPT App Directory, both of which require accurate per-tool readOnlyHint/destructiveHint annotations.

Suggested fix

At minimum, don't assert specific incorrect values when the actual behavior is unknown — omitting the field (or a documented neutral default) is more honest than a false false. Ideally, expose a way to set per-assistant annotations from application config (e.g. a graphs.<name>.annotations key in langgraph.json/the MCP-specific config, mirroring the MCP spec's ToolAnnotations schema) so applications with real read-only/destructive/idempotent distinctions among their tools can surface them accurately.

Environment: langgraph-api==0.7.90 (deployed), reproduced by source diff against 0.14.1 (latest as of 2026-09-17).