Skip to content
Development
Skill

/jupyter

This skill covers building PyWry widgets for Jupyter notebooks via MCP tools.

From plugin
pywry
9318 skills1 agent2 commands1 MCP
Install
$ npx -y skills add deeleeramone/PyWry --skill jupyter --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/jupyter

Context preview

The summary Claude sees to decide when to auto-load this skill.

This skill covers building PyWry widgets for Jupyter notebooks via MCP tools.

SKILL.md

jupyter.SKILL.md

Jupyter Notebook Skill

This skill covers building PyWry widgets for Jupyter notebooks via MCP tools.

There are **two approaches** for displaying widgets in Jupyter:

| Approach | Best For | Requires | |----------|----------|----------| | **AnyWidget** (recommended) | Native Jupyter integration, bidirectional comms | `pip install 'pywry[notebook]'` | | **IFrame** (fallback) | When anywidget unavailable | MCP server in headless mode |

---

Approach 1: AnyWidget (Recommended)

AnyWidget provides native Jupyter widget integration with traitlet-based bidirectional communication. No iframe, no server - just native Jupyter widgets.

Architecture

┌─────────────────────────────────────────────────────────┐
│  Jupyter Notebook                                       │
│  ┌───────────────────────────────────────────────────┐  │
│  │  Cell [1]: # Code from MCP agent                  │  │
│  │            from pywry.widget import PyWryWidget   │  │
│  │            widget = PyWryWidget(                  │  │
│  │                content="<div>...</div>",          │  │
│  │                height="400px"                     │  │
│  │            )                                      │  │
│  │            widget  # Display in cell              │  │
│  ├───────────────────────────────────────────────────┤  │
│  │  Output: ┌─────────────────────────────────────┐  │  │
│  │          │  [Native Jupyter Widget]            │  │  │
│  │          │  Buttons, Charts, Tables, etc.      │  │  │
│  │          └─────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
         ▲
         │ Traitlet sync (bidirectional)
         ▼
┌─────────────────────────────────────────────────────────┐
│  Python Kernel                                          │
│  PyWryWidget instance with .on() event handlers         │
└─────────────────────────────────────────────────────────┘

MCP Workflow for AnyWidget

When asked to create an interactive widget in Jupyter with anywidget installed:

1. **Use `build_div` to build HTML content** 2. **Provide Python code for the user to run**

The MCP agent **cannot** directly instantiate Python objects in the user's kernel. Instead, provide code the user can execute.

Example: Parameter Tuning Widget

When user asks: "Create a widget to tune learning rate and model type"

**Step 1**: Build the HTML content using MCP tools:

{
  "tool": "build_div",
  "arguments": {
    "component_id": "output",
    "content": "Adjust parameters below",
    "style": "padding: 1rem; min-height: 100px;"
  }
}

**Step 2**: Provide this Python code to the user:

from pywry.widget import PyWryWidget
from pywry.toolbar import Toolbar, Slider, Select, Option, Button

# Build toolbar
toolbar = Toolbar(position="inside", items=[
    Slider(label="Learning Rate", event="lr", min=0.001, max=0.1, step=0.001, value=0.01),
    Select(label="Model", event="model", options=[
        Option(label="Linear", value="linear"),
        Option(label="Random Forest", value="rf")
    ]),
    Button(label="Train", event="train", variant="primary")
])

# Build HTML with toolbar
html = f'''
<div id="output" style="padding: 1rem; min-height: 100px;">
    Adjust parameters and click Train
</div>
{toolbar.render()}
'''

# Create and display widget
widget = PyWryWidget(content=html, height="350px")

# Handle events
def on_train(data, event_type, label):
    print(f"Training with: {data}")
    widget.emit("pywry:set-content", {"id": "output", "html": "<p>Training...</p>"})

widget.on("train", on_train)
widget  # Display in cell

AnyWidget Classes

| Class | Use Case | |-------|----------| | `PyWryWidget` | General HTML/toolbar widgets | | `PyWryPlotlyWidget` | Charts with Plotly.js bundled | | `PyWryAgGridWidget` | Data tables with AG Grid bundled |

PyWryPlotlyWidget Example

from pywry.widget import PyWryPlotlyWidget

widget = PyWryPlotlyWidget(
    figure={"data": [{"x": [1,2,3], "y": [4,5,6], "type": "scatter"}]},
    height="450px"
)

# Handle plot click events
widget.on("plotly_click", lambda data, *_: print(f"Clicked: {data}"))
widget

PyWryAgGridWidget Example

from pywry.widget import PyWryAgGridWidget
import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": ["x", "y", "z"]})

widget = PyWryAgGridWidget(
    data=df.to_dict("records"),
    columns=[{"field": "A"}, {"field": "B"}],
    height="400px"
)

# Handle row selection
widget.on("row_selected", lambda data, *_: print(f"Selected: {data}"))
widget

---

Approach 2: IFrame (Fallback)

When anywidget is not installed, use the MCP server in headless mode to serve widgets via HTTP.

Architecture

┌─────────────────────────────────────────────────────────┐
│  Jupyter Notebook                                       │
│  ┌───────────────────────────────────────────────────┐  │
│  │  Cell [1]: from IPython.display import IFrame     │  │
│  │            IFrame("http://localhost:8765/widget/  │  │
│  │                   abc123", width="100%",          │  │
│  │                   height=400)                     │  │
│  ├───────────────────────────────────────────────────┤  │
│  │  Output: ┌─────────────────────────────────────┐  │  │
│  │          │  [Your Widget Rendered Here]        │  │  │
│  │          │  Buttons, Charts, Tables, etc.      │  │  │
│  │          └─────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
         ▲
         │ HTTP (iframe src)
         ▼
┌─────────────────────────────────────────────────────────┐
│  PyWry Widget Server (localhost:8765)                   │
│  Serves widget HTML at /widget/{widget_id}              │
└─────────────────────────────────────────────────────────┘

MCP Tool Workflow (IFrame Mode)

Step 1: Create the Widget

Read more
Ships withpywry

PyWry is a cross-platform app factory, rendering engine and UI toolkit for Python that produces native desktop, web, and notebook experiences from a single API.

Get the whole plugin

Other skills on pywry.