PrefectHQ/fastmcp · error · ToolError

elicitation via server-initiated requests is unavailable on

Error message

elicitation via server-initiated requests is unavailable on 2026-07-28 connections.

What it means

On modern-protocol (2026-07-28 era) connections, server-initiated elicitation was removed (SEP-2577) because there is no back-channel for server-initiated requests. ctx.elicit() detects this era up front via _is_modern_protocol() and raises a clear ToolError instead of letting the wire call fail with the SDK's opaque 'Method not found'. Handshake-era connections are unaffected.

Source

Thrown at fastmcp_slim/fastmcp/server/context.py:1089

            ``ctx.input_responses`` / ``ctx.request_state`` when the task re-runs.
        """
        config = parse_elicit_response_type(
            response_type,
            response_title=response_title,
            response_description=response_description,
        )

        if self.is_background_task:
            # Background tasks gather input with the guard/return pattern, not
            # imperative elicitation — the worker never blocks on a client
            # round-trip. Fail fast with the guidance to use InputRequiredResult.
            raise ToolError(_TASK_ELICIT_ERROR)
        # Foreground push path: server-initiated elicitation needs a back-channel,
        # which the 2026-07-28 era removed (SEP-2577). Raise a clear era-aware
        # error before hitting the wire instead of the SDK's opaque "Method not
        # found". Handshake-era behavior is unchanged.
        if self._is_modern_protocol():
            raise ToolError(_ELICIT_MODERN_ERROR)
        # Standard request mode: use session.elicit directly
        result = await self.session.elicit(
            message=message,
            requested_schema=config.schema,
            related_request_id=self.request_id,
        )

        if result.action == "accept":
            return handle_elicit_accept(config, result.content)
        elif result.action == "decline":
            return DeclinedElicitation()
        elif result.action == "cancel":
            return CancelledElicitation()
        else:
            raise ValueError(f"Unexpected elicitation action: {result.action}")

    def _make_state_key(self, key: str) -> str:
        """Create session-prefixed key for state storage."""

View on GitHub (pinned to 1f02114297)

Solutions

  1. Remove imperative ctx.elicit() from tools served to modern-era clients; use the InputRequiredResult guard pattern instead.
  2. Pin the client connection to the handshake-era protocol if elicitation is required and the era negotiation is controllable.
  3. Feature-detect the era (ctx._is_modern_protocol() / negotiated version) and branch to a non-interactive flow.
  4. Communicate required input through the tool's arguments so no mid-run elicitation is needed.

Example fix

// before
async def tool(ctx: Context):
    res = await ctx.elicit("Enter token", TokenSchema)
// after
async def tool(token: str, ctx: Context):  # collect input via tool args
    ...
# or modern-era guard: return InputRequiredResult(input_requests=[...])
Defensive patterns

Strategy: try-catch

Validate before calling

if ctx._is_modern_protocol():
    # server-initiated elicitation unavailable (SEP-2577); use guard pattern or tool args
    pass

Try / catch

try:
    res = await ctx.elicit(msg, config)
except ToolError as e:
    if "unavailable" in str(e) or "2026-07-28" in str(e):
        res = await fallback_input_flow(config)  # e.g. end tool, ask for args
    else:
        raise

Prevention

When it happens

Trigger: Calling await ctx.elicit(...) from any tool/prompt/resource handler while the client is connected with the 2026-07-28 protocol era negotiated (and not in a background task).

Common situations: Servers upgraded to the modern protocol era whose tools still call ctx.elicit(); clients that negotiated the newer protocol version, breaking previously working elicitation flows; mixed-version fleets where some clients connect old-era and others new-era.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/d2148726c23d25c2. Report an issue: GitHub.