Skip to content

feat: expose progress_callback in ServerSession methods#2041

Open
BryceEWatson wants to merge 6 commits into
modelcontextprotocol:mainfrom
BryceEWatson:fix/1671-serversession-progress-callback
Open

feat: expose progress_callback in ServerSession methods#2041
BryceEWatson wants to merge 6 commits into
modelcontextprotocol:mainfrom
BryceEWatson:fix/1671-serversession-progress-callback

Conversation

@BryceEWatson

@BryceEWatson BryceEWatson commented Feb 12, 2026

Copy link
Copy Markdown

Fixes #1671

Motivation and Context

The ServerSession high-level methods for sending requests to clients (create_message, elicit_form, elicit_url) 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.

ClientSession.call_tool() already exposes progress_callback for the client→server direction. This PR adds the same support for the server→client direction, bringing the Python SDK into parity with the TypeScript SDK's RequestOptions.onprogress.

How Has This Been Tested?

  • Two new E2E tests added to tests/shared/test_progress_notifications.py:
    • test_server_create_message_progress_callback: verifies progress callbacks work during sampling requests via MCPServer + Client
    • test_server_elicit_form_progress_callback: verifies progress callbacks work during elicitation requests via MCPServer + Client
  • After rebasing onto current main, the full test suite passes locally (uv run pytest), uv run pyright reports 0 errors, and uv run ruff check . is clean. CI is green on all checks.

Breaking Changes

No. All new parameters default to None, maintaining full backward compatibility.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Approach: Mirrors the existing ClientSession.call_tool() pattern — adds progress_callback: ProgressFnT | None = None to each method signature and passes it through to send_request().

Files changed (4):

  • src/mcp/server/session.py — Core: added param to create_message() (all overloads + impl), elicit(), elicit_form(), elicit_url()
  • src/mcp/server/elicitation.py — Helpers: passthrough in elicit_with_validation() and elicit_url()
  • src/mcp/server/mcpserver/context.py — Context API: passthrough in Context.elicit() and Context.elicit_url()
  • tests/shared/test_progress_notifications.py — 2 new E2E tests

Intentionally excluded: list_roots() and send_ping() — these are short-lived requests where progress tracking isn't meaningful.

AI assistance disclosure

I used AI assistance while writing this change. I've reviewed and tested every line, understand the mechanism (send_request already accepts progress_callback and maps it to on_progress; these convenience methods just weren't forwarding it), and can answer questions on it directly.

…elicit_form()

Add progress_callback parameter to ServerSession methods that send
requests to clients, matching the pattern already used by
ClientSession.call_tool(). This brings the Python SDK into parity
with the TypeScript SDK's RequestOptions.onprogress support.

The MCP spec supports bidirectional progress notifications, and
BaseSession.send_request() already accepts progress_callback, but
the ServerSession convenience methods were not exposing it.

Fixes modelcontextprotocol#1671

Github-Issue: modelcontextprotocol#1671
The if-guards checking for progress_token in context.meta always
evaluate to True when progress_callback is provided, so the false
branches are never taken. Mark with pragma: no branch to satisfy
100% coverage requirement.
Merge upstream/main into fix/1671-serversession-progress-callback.
Resolved import conflict in mcpserver/server.py by keeping both the
new ProgressFnT import and the expanded mcp.types imports from the
lowlevel Server decorator refactor (modelcontextprotocol#1985).
@BryceEWatson

Copy link
Copy Markdown
Author

The pre-commit failure is unrelated to this PR — the readme-v1-frozen hook (added in #2045) fails on all branches including main (CI run). All 20 test jobs, conformance tests, and readme-snippets pass.

Merge upstream/main which included major refactors:
- Context class moved from server.py to mcpserver/context.py (modelcontextprotocol#2203)
- Lowlevel Server decorators replaced with on_* kwargs (modelcontextprotocol#1985)
- Docstring formatting standardized with periods (modelcontextprotocol#2095)
- mcp.shared.progress module removed (modelcontextprotocol#2080)

Resolved conflicts by:
- Taking upstream server.py (Context class removed)
- Adding progress_callback to new context.py
- Keeping progress_callback docstrings with upstream period style
- Restoring RequestContext import for new tests
- Updating tests to use ctx: Context injection pattern
@BryceEWatson BryceEWatson force-pushed the fix/1671-serversession-progress-callback branch from 606d106 to b23b702 Compare March 7, 2026 22:49
Sync the progress_callback feature branch onto current upstream/main, which
had undergone a large refactor since the branch was last updated (dispatcher
extraction, ProgressFnT moved from mcp.shared.session to mcp.shared.dispatcher,
removal of the experimental tasks modules, and a test reorganization).

Conflict resolution:
- src/mcp/server/session.py: take upstream's import block (ProgressFnT now
  comes from mcp.shared.dispatcher). The progress_callback pass-throughs on
  create_message/elicit/elicit_form/elicit_url auto-merged onto upstream's
  refactored send_request, which already accepts progress_callback.
- src/mcp/server/mcpserver/context.py: keep both upstream's LoggingLevel import
  and the ProgressFnT import (relocated to mcp.shared.dispatcher).
- tests/shared/test_progress_notifications.py: upstream deleted this pre-existing
  file in its test reorg. Re-add it containing only this PR's two feature tests
  (create_message and elicit_form progress_callback pass-through), adapted to the
  new client callback API (mcp.client.ClientRequestContext).

Verified locally: ruff format/lint clean, pyright clean, full suite green
(2388 passed serially), coverage 100%.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant