docs: correct ROADMAP's elicitation/sampling/roots next-tier bullet (#411) - #413
Conversation
…411) Investigated wiring the pinned SDK's MRTR support (Resolve/Elicit, mcp 2.0.0) into the needs_confirm cold-graph gates and stopped short of implementing: a Resolve-annotated parameter is dropped from the tool's published inputSchema and is always resolver-filled, so a capability-less client gets a hard MCPError instead of today's needs_confirm envelope — incompatible with keeping confirm client-suppliable. Spec rev 2026-07-28 also deprecated sampling and roots (SEP-2577), so the roadmap's roots geofence bullet is corrected to point at #409's PLACEROOT_HOME instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lead review (loop)Docs-only diff verified; suite green on the branch (2368 passed, ruff clean, matching its off-main baseline). This is the right outcome and the right write-up: the two SDK facts (Resolve-annotated params dropped from published inputSchema via I added |
… ROADMAP note list_roots's deprecation marker sits on mcp.server.session.ServerSession (mcp/server/session.py:316), not under mcp.client.session; and isochrone carries no needs_confirm gate — the gated tools are route/from_to/ meeting_point/suggest_areas/find_places-within plus warmup_city's own confirm gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YCuTkstNj5KscUQ9u8cLMK
# Conflicts: # docs/ROADMAP.md
Summary
Closes the investigation half of #411. Part 1 (wiring MRTR/
Resolve/Elicitinto the cold-graphneeds_confirmgates) was investigated against the pinned SDK and stopped short of implementation — see the finding below. Part 2 (ROADMAP correction) ships in this PR.Part 1 finding: SDK's Resolve/Elicit cannot express this without breaking the hard requirements
Investigated
mcp2.0.0'sAnnotated[T, Resolve(fn)]+Elicit(message, schema)MRTR support (.venv/lib/python3.11/site-packages/mcp/server/mcpserver/resolve.py) end-to-end, including a throwaway in-process proof registering a realMCPServertool with aResolve-annotatedconfirmparameter.Two facts, confirmed both by reading the SDK and by running the proof:
inputSchemaentirely.Tool.from_functioninmcp/server/mcpserver/tools/base.py:92-99doesskip_names.extend(resolved_params)before callingfunc_metadata(fn, skip_names=skip_names, ...). In the proof, a tool declared withlat, lon, mode, confirm: Annotated[bool, Resolve(...)]published aninputSchemawith onlylat, lon, mode—confirmvanished. It cannot be set by the caller at all onceResolve-annotated.resolve.py:665-700(_require_capability) raisesMCPError(MISSING_REQUIRED_CLIENT_CAPABILITY)when the client hasn't declared the elicitation capability. In the proof, callingresolve_argumentswithconfirm=Truealready in the tool args (simulating a legacy client explicitly retrying with the hand-rolled protocol) still raised:Both of these directly conflict with #411's acceptance criteria:
confirmmust stay client-suppliable, and capability-less clients must keep today'sneeds_confirmenvelope byte-identically. There is no way to keepconfirmin the published schema and have it resolver-filled — the SDK'sskip_namesmechanism is unconditional. And there is no documented/observed fallback path when the client lacks the capability — it's a hardMCPError, which would change behavior for every existing capability-less client callingroute/from_to/isochrone/find_places(within=...)today.This also rules out reusing the two existing
func_metadatamonkeypatches (_publish_from_keyword,_publish_output_schemasinsrc/placeroot/server.py:5364/5432) to paper over the schema-visibility gap:_publish_from_keywordrebuildstool.parameters/tool.fn_metadataafter registration, buttool.resolved_params/tool.resolver_plans(which drive the actual resolve-vs-error-vs-fallback behavior at call time) are fixed atTool.from_functiontime and are untouched by that patch — so even forcingconfirmback into the displayed schema wouldn't fix the hard-error-on-missing-capability problem underneath it.Per #411's own stop condition ("If investigation reveals the SDK's Resolve/Elicit CANNOT express this without breaking schema publication or the existing monkeypatches, STOP part 1... An honest negative result is acceptable; a contorted implementation is not"), Part 1 is not shipped. Ambiguity-candidate elicitation (
ambiguous_place/ambiguous_area) was out of scope per the issue and wasn't separately investigated — noted as an open follow-up, though it would hit the same schema/capability wall for any parameter that must stay settable by capability-less clients.Part 2: ROADMAP correction
docs/ROADMAP.md's next-tier "Elicitation + sampling adoption" bullet rewritten with a dated note (2026-08-24, MRTR/elicitation for confirm gates + ROADMAP correction for deprecated elicitation/sampling/roots #411) citing the finding above; theverify_claims-via-sampling idea is dropped outright (sampling deprecated per the same spec rev, 2026-07-28).mcp/client/session.py:1288carries the deprecation marker onlist_roots), and feat: PLACEROOT_HOME resolution bias — geofence for Springfield-class ambiguity (#406) #409 already shipped the actual geofence differently, viaPLACEROOT_HOME, with a stubbed always-Noneresolve_home_from_roots()rather than building against a walked-back capability.docs/ROADMAP.md"Appendix: sequencing sketch") updated to match — drops the stale "MCP roots geofence; elicitation upgrade" / "sampling inverify_claims" references.North-star: this is both a spec-change opportunity (MRTR is new, real SDK surface) and competitive tracking against mapbox/mcp-server#245, which tracks the same 2026-07-28 migration.
Test plan
uv run pytest -q— 2368 passed, 0 failed (baseline for this branch, offmainat 2790e91; matches, no regressions)uv run ruff check .— cleanCHANGELOG.md+docs/ROADMAP.mdonlydocs/benchmarks.md/docs/benchmarks-vs.mdregen neededCHANGELOG.md### Changedentry added (docs-only correction, not a feature)🤖 Generated with Claude Code
Closes #411 — part 1 is a documented negative result (revisit condition recorded in the corrected ROADMAP bullet); part 2 shipped.