* fix: restore request context in StatefulProxyClient handlers
StatefulProxyClient reuses sessions across requests, so its receive-loop
task inherits a stale request_ctx ContextVar from the first request.
Server-initiated messages (elicitation, sampling, etc.) that depend on
related_request_id routing get sent to a closed stream and hang forever.
Closes#3169
* chore: Update SDK documentation
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
* fix: guard client pagination loops against misbehaving servers
Treat empty/falsy nextCursor as end-of-pagination and detect cursor
cycles across all client list methods and the server context proxy
helper.
* chore: Update SDK documentation
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
Moves relay_elicitation() into elicitation.py so it can reuse
handle_task_input() for the Redis push instead of duplicating that logic.
notifications.py just detects the trigger and calls it.
Also fixes the related-task metadata key from modelcontextprotocol.io/ to
io.modelcontextprotocol/ to match the current spec:
https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a background task calls ctx.elicit(), the notification subscriber now
detects the input_required notification and sends a standard elicitation/create
request to the client via session.elicit(). The client's elicitation_handler
fires, and the relay pushes the response to Redis for the blocked worker.
This means clients can respond to background task elicitation using the same
elicitation_handler they'd use for any other elicitation — no need to interact
with Redis or call handle_task_input() directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Rename ui= to app= and consolidate ToolUI/ResourceUI into AppConfig
* Remove backward-compat aliases for ToolUI/ResourceUI/ui_to_meta_dict
* Add extra=allow to AppConfig model_config for forward compatibility
* generate-cli: auto-generate SKILL.md alongside CLI script
generate-cli now produces a SKILL.md agent skill file next to the CLI
script, documenting every tool's exact invocation syntax, parameter
flags, and types. Agents can use the CLI immediately without discovery.
* Use uv run --with fastmcp in generated SKILL.md invocations
* Fix skill generation issues from review
- Escape pipe chars in union type labels so markdown tables render
- Boolean params omit <value> placeholder in example invocations
- Quote YAML frontmatter values to handle special chars in names
- Match cyclopts camelCase→snake_case in flag derivation
- Use four-backtick fence for nested code block in docs
* Replace --skill/--no-skill with just --no-skill
* Escape quotes in YAML frontmatter description
* Strip newlines from param descriptions in skill table rows
* Detect boolean union types for flag placeholder
Replace 1300+ lines of mock-heavy unit tests with 391 lines of integration
tests using real Client(mcp) connections and memory:// Docket backend.
- test_context_background_task.py: 17 tests covering report_progress delta
tracking, elicitation flow, edge cases, and fail-fast on push failure
- test_notifications.py: 2 E2E tests for notification queue lifecycle
- context.py: report_progress uses delta tracking via increment() instead
of set_current() (which doesn't exist), stores progress in Redis for
background tasks
- elicitation.py: replace polling with BLPOP for efficient blocking wait,
fail-fast on notification push failure, use get_task_context() for
authoritative session_id
- handlers.py: subscriber cleanup on session disconnect via
_exit_stack.push_async_callback()