Skip to content

ServerSession methods (create_message, elicit_form) don't expose progress_callback parameter #1671

Description

@maxisbey

Summary

The ServerSession high-level methods for sending requests to clients (create_message, elicit_form) don't expose the progress_callback parameter, even though the underlying BaseSession.send_request() fully supports it.

This means servers can't easily receive progress notifications from clients during sampling or elicitation requests.

Current Behavior

# ServerSession.elicit_form() - no progress_callback parameter
async def elicit_form(
    self,
    message: str,
    requestedSchema: types.ElicitRequestedSchema,
    related_request_id: types.RequestId | None = None,
) -> types.ElicitResult:
    return await self.send_request(...)  # progress_callback not passed through

# ServerSession.create_message() - same issue
async def create_message(
    self,
    messages: list[types.SamplingMessage],
    *,
    max_tokens: int,
    # ... other params ...
    related_request_id: types.RequestId | None = None,
) -> types.CreateMessageResult:
    return await self.send_request(...)  # progress_callback not passed through

Expected Behavior

# Should be able to pass progress_callback
result = await server_session.elicit_form(
    message="Please provide your details",
    requestedSchema=schema,
    progress_callback=lambda progress, total, msg: print(f"Progress: {progress}/{total} - {msg}")
)

result = await server_session.create_message(
    messages=messages,
    max_tokens=1000,
    progress_callback=lambda progress, total, msg: print(f"Sampling progress: {progress}/{total}")
)

Context

  • The MCP spec supports bidirectional progress notifications - clients CAN send notifications/progress back to servers during request handling
  • BaseSession.send_request() already supports progress_callback parameter
  • ClientSession.call_tool() exposes progress_callback for the client→server direction
  • The TypeScript SDK exposes this via RequestOptions.onprogress in both createMessage() and elicitInput()
  • Tests in tests/shared/test_progress_notifications.py demonstrate the bidirectional flow works

Suggested Fix

Add progress_callback: ProgressFnT | None = None parameter to:

  • ServerSession.create_message()
  • ServerSession.elicit_form()
  • Any other ServerSession methods that send requests to clients

And pass it through to send_request().

Activity

  1. added
    enhancementRequest for a new feature that's not currently supported
    ready for workEnough information for someone to start working on
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    on Nov 25, 2025
  2. added a commit that references this issue on Feb 12, 2026
    8d1257f
  3. BryceEWatson commented on Feb 12, 2026

    @BryceEWatson

    I'd like to take this on — PR incoming.

    I've added progress_callback: ProgressFnT | None = None to create_message(), elicit_form(), elicit_url(), and the deprecated elicit() wrapper on ServerSession, plus threaded it through the elicitation.py helpers and Context API. The approach mirrors how ClientSession.call_tool() already handles it.

    Includes E2E tests for both sampling and elicitation flows. All existing tests pass.

  4. added
    needs decisionIssue is actionable, needs maintainer decision on whether to implement
    and removed
    ready for workEnough information for someone to start working on
    on Apr 17, 2026
  5. BryceEWatson commented on Jun 20, 2026

    @BryceEWatson

    Hi @felixweinberger @maxisbey — this one lost ready for work and picked up needs decision back in April, so rather than leave it in limbo I wanted to ask for a keep-or-close call.

    A few things that might make the decision easy:

    • It closes an internal asymmetry rather than adding new surface. send_request() already accepts progress_callback and maps it to on_progress; the ServerSession convenience methods (create_message, elicit_form, elicit_url) just don't forward it. The client direction already exposes it (ClientSession.call_tool(progress_callback=...), feat: support progress_callback propagation in ClientSession #1248), so this restores client/server symmetry.
    • It follows the existing public convention — the same per-method progress_callback kwarg already on ServerSession.send_request and Client.call_tool.
    • It's spec- and parity-backed. The 2025-06-18 progress utility allows progress notifications on requests from either party, and sampling/elicitation are server-initiated; the TS SDK already supports this (Server.createMessage/elicitInput take RequestOptions, which carries onprogress). Python's ServerSession is the remaining gap.
    • feat: expose progress_callback in ServerSession methods #2041 is ready: it implements exactly the change described in the issue body, is rebased on current main and green, every new param defaults to None (non-breaking), with two E2E tests on the sampling and elicitation paths.

    I realize the issue isn't ready for work right now — I'm really just asking whether you'd be open to clearing the needs decision. "Not until v2 settles" is a perfectly good answer too; I'll keep the branch rebased either way. Happy to add tests or adjust the approach.

    Disclosure: I used AI assistance on this change. I've reviewed and tested every line, understand the mechanism, and can answer questions on it directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Moderate issues affecting some users, edge cases, potentially valuable featureenhancementRequest for a new feature that's not currently supportedneeds decisionIssue is actionable, needs maintainer decision on whether to implement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions