Skip to content

feat(mcp): non-blocking restart_kernel with progress reporting#923

Merged
rgbkrk merged 2 commits intomainfrom
quill/restart-kernel-deps-wait
Mar 18, 2026
Merged

feat(mcp): non-blocking restart_kernel with progress reporting#923
rgbkrk merged 2 commits intomainfrom
quill/restart-kernel-deps-wait

Conversation

@rgbkrk
Copy link
Copy Markdown
Member

@rgbkrk rgbkrk commented Mar 18, 2026

Summary

Improves MCP notebook API performance and user feedback when installing dependencies:

  • create_notebook(dependencies=[...]): Pre-install packages before first kernel launch. Eliminates the add-then-restart cycle for agents setting up new notebooks with dependencies.
  • restart_kernel() timeout: No longer blocks indefinitely on slow environment preparation (120s timeout). Returns helpful error instead of hanging.
  • Progress reporting: Collects environment preparation messages during restart (e.g., "Downloading 3/10 packages...") and returns them to MCP callers for visibility.

Fixes issue where adding large packages (e.g., mlx-whisper) would block agents for minutes with zero feedback.

Test Plan

  • Reviewer can call create_notebook(dependencies=["pandas", "requests"]) and verify kernel launches with deps pre-installed (no restart needed)
  • Reviewer can add a large dependency and call restart_kernel(), verifying timeout after ~120s and progress messages in output
  • Verify env_progress events appear in execution event subscriptions

PR submitted by @rgbkrk's agent, Quill

…v deps

Add three improvements to the MCP notebook API:

1. **create_notebook(dependencies=[...])**: Pre-install packages before first kernel launch, eliminating the add-then-restart cycle. Dependencies are added to notebook metadata and kernel is restarted once to pick them up.

2. **restart_kernel() timeout (120s)**: No longer blocks indefinitely on slow environment installations. Returns an error if deps take longer than 2 minutes instead of hanging the agent.

3. **Progress reporting**: Collects EnvProgressPhase broadcasts during kernel restart (e.g. "Downloading 3/10 packages...") and returns them to the MCP caller. Enables agents to see what's happening during large package installs.

Implementation:
- restart_kernel() releases state lock before LaunchKernel, unblocking other operations
- Uses tokio::select! to race LaunchKernel response vs EnvProgress broadcasts
- Exposes EnvProgress events to Python via ExecutionEvent subscription (previously dropped)
- env_progress_message() converts progress phases to human-readable strings

This fixes the issue where agents adding large packages (mlx-whisper, etc) would block for minutes with zero feedback.
@github-actions github-actions bot added mcp MCP server and agent integrations quill PR authored by Quill Agent 🦆 labels Mar 18, 2026
@rgbkrk rgbkrk requested a review from Copilot March 18, 2026 01:36
The Rust implementation returns Vec<String> (progress messages) but the
type stub still declared the return as None, causing ty type checker to
fail in CI.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the MCP notebook workflow around dependency installation and kernel restarts by adding dependency preconfiguration at notebook creation time, introducing restart timeouts, and surfacing environment-prep progress to callers/subscribers.

Changes:

  • Add dependencies=[...] to create_notebook() to record deps in metadata and attempt to restart so the kernel picks them up.
  • Make restart_kernel() return progress messages and enforce a 120s timeout instead of potentially blocking indefinitely.
  • Emit env_progress execution events by mapping NotebookBroadcast::EnvProgress into the Python subscription stream.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
python/nteract/src/nteract/_mcp_server.py Adds MCP API parameters/return fields for deps + restart progress; wires through to Python session.
crates/runtimed-py/src/subscription.rs Converts daemon EnvProgress broadcasts into env_progress execution events + message formatting.
crates/runtimed-py/src/session_core.rs Implements restart timeout + concurrent progress collection; changes restart return type to Vec<String>.
crates/runtimed-py/src/session.rs Updates sync Python bindings to return progress messages from restart_kernel().
crates/runtimed-py/src/async_session.rs Updates async Python bindings docs/behavior for restart_kernel() returning progress messages.
crates/runtimed-py/Cargo.toml Adds kernel-env dependency for EnvProgressPhase.
Cargo.lock Locks the added kernel-env dependency for runtimed-py.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +409 to +413
if let Some(NotebookBroadcast::EnvProgress { env_type, phase }) = msg {
let text = crate::subscription::env_progress_message(&phase);
progress_messages.push(format!("[{}] {}", env_type, text));
}
// Continue waiting for launch response
Comment on lines 342 to +349
/// Restart the kernel with auto environment detection.
///
/// Returns a list of progress messages emitted during environment
/// preparation (e.g. "Installing 3 packages..."). Empty if cached.
pub(crate) async fn restart_kernel(
state: &Arc<Mutex<SessionState>>,
wait_for_ready: bool,
) -> PyResult<()> {
) -> PyResult<Vec<String>> {
Comment on lines +660 to +662
# Add dependencies to notebook metadata
for dep in dependencies:
await session.add_uv_dependency(dep)
Comment on lines +640 to +642
The kernel starts automatically. If dependencies are provided, they are
added to notebook metadata before the kernel launches, so the environment
is prepared on first start (no restart needed).
Comment on lines +664 to +667
# The daemon may have auto-launched a kernel (without these deps).
# Restart to ensure the kernel picks up the inline deps.
with contextlib.suppress(Exception):
await session.restart_kernel(wait_for_ready=True)
Comment on lines +718 to +719
Reports environment preparation progress (package downloads, installs)
via MCP log notifications while waiting. Times out after 120s.
@rgbkrk rgbkrk merged commit 9f69aa0 into main Mar 18, 2026
38 of 42 checks passed
@rgbkrk rgbkrk deleted the quill/restart-kernel-deps-wait branch March 18, 2026 02:19
rgbkrk added a commit that referenced this pull request Mar 18, 2026
…tub types

Audit of merged #923 + #924 found several issues:

Rust (session_core.rs):
- collect_outputs: get_cells() + find → get_cell() (single-cell lookup)
- get_cell_metadata: get_cells() + find → handle.get_cell_metadata()
  with clone-handle-drop-lock pattern

MCP server:
- replace_match: get_cell() → get_cell_source() (only needs source)
- replace_regex: same fix

Type stubs (.pyi):
- move_cell: None → str (returns new position)
- get_cell: Cell | None → Cell (raises on missing, never None)
- set_cell_source_hidden: None → bool
- set_cell_outputs_hidden: None → bool
- set_cell_tags: None → bool
All fixed for both Session and AsyncSession.
rgbkrk added a commit that referenced this pull request Mar 18, 2026
…tub types (#927)

Audit of merged #923 + #924 found several issues:

Rust (session_core.rs):
- collect_outputs: get_cells() + find → get_cell() (single-cell lookup)
- get_cell_metadata: get_cells() + find → handle.get_cell_metadata()
  with clone-handle-drop-lock pattern

MCP server:
- replace_match: get_cell() → get_cell_source() (only needs source)
- replace_regex: same fix

Type stubs (.pyi):
- move_cell: None → str (returns new position)
- get_cell: Cell | None → Cell (raises on missing, never None)
- set_cell_source_hidden: None → bool
- set_cell_outputs_hidden: None → bool
- set_cell_tags: None → bool
All fixed for both Session and AsyncSession.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mcp MCP server and agent integrations quill PR authored by Quill Agent 🦆

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants