Repository navigation
feat: Add opt-in WebMCP tools for Shiny apps - #2513
Draft
karangattu wants to merge 11 commits into
Draft
karangattu wants to merge 11 commits into
karangattu wants to merge 11 commits into
Conversation
|
Very glad to see this being worked for shiny! Thanks for taking it on. Excited to use this. |
# Conflicts: # CHANGELOG.md
crypto.randomUUID() is unavailable in insecure contexts, so every tool that flushed failed on plain-http hosts. The flush input is sent with event priority, which always resends, so a counter is sufficient. Tool schemas now default additionalProperties to False. Unknown keys previously passed validation and surfaced as a TypeError from the keyword call, which the sanitizer turned into an opaque error.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR lets browser agents use existing Shiny apps through WebMCP. The agent and the person share the same open app. Both can change its controls and read its results.
The feature is experimental and off by default. Set
SHINY_WEBMCP=1to enable it for an existing app. Core apps can also useApp(..., webmcp=True). Browsers without WebMCP still run the app normally.Browser support
WebMCP browser support is evolving (status as of October 1, 2026). This PR requires
document.modelContext.registerTooland a compatible browser agent.chrome://flags/#enable-webmcp-testingand restart for local testing; an origin trial is available from Chrome 149.When the required API is absent, Shiny skips tool registration and the app continues to work normally. This PR does not bundle a WebMCP polyfill.
SHINY_WEBMCP=1enables Shiny's integration; it does not enable the browser API or enroll the site in an origin trial.Sources: WebMCP browser and agent implementation status, Chrome setup.
When to use each tool
These tools work at different levels. Shiny's Playwright controllers are helpers for browser controls. Choose the tool based on what you need to do.
local_serverTools for existing apps
Shiny provides four tools:
shiny_describe_app. It lists visible supported inputs, their current values, allowed arguments, available actions, and output status.shiny_set_inputs. It makes sure that values are allowed, updates the actual controls, and returns results after Shiny finishes its queued reactive updates.shiny_read_outputs. Results include status information and a length limit. Visual, HTML, and data-frame outputs report that they are unsupported.shiny_invoke_action. Only buttons markeddata-webmcp="action"are available. Usedata-webmcp="exclude"to omit an element and its children from automatic discovery.Each tool has a schema, which defines its allowed arguments. Shiny updates schemas when controls, choices, or limits change. Input IDs keep their module prefixes.
The tools omit hidden controls, password inputs, and file inputs. They reject changes to disabled controls and choices. Calls use the session's existing WebSocket connection between the browser and server.
The browser receives a response after Shiny sends the related output updates. Calls handle lost connections and cancellation, and stop waiting after 30 seconds. They do not wait for background tasks. Cancellation does not undo Python work that already started.
Tools written in Python
While automatic tools let an agent interact with the UI, you can also write custom Python functions that agents can call directly using the
@webmcp.tooldecorator. This is useful for performing calculations, querying backend databases, or returning structured data.Basic Example
Decorate your function inside the server function (or at the top level in Shiny Express):
How it works
def) or asynchronous (async def). Return values must be JSON-serializable (e.g. dicts, lists, numbers, strings).input_schema(a standard JSON Schema object). Shiny usesjsonschemato validate the agent's arguments before invoking your Python function.input.x()) in an isolated context without creating reactive dependencies that trigger unwanted reruns of outputs.read_only=Trueindicates the tool just reads data without changing state, whileconsequential=Trueindicates significant side effects. These provide guidance to the agent's planner.Example: Quickstart & How to Use
This feature allows a person and an AI browser agent to collaborate in the same open Shiny session. The agent has access to two types of tools:
shiny_*): Built-in tools that let the agent discover inputs, modify controls, click exposed buttons, and read outputs.@webmcp.tool): Domain-specific tools you define in Python to calculate metrics or return structured data directly to the agent.1. Run the sales explorer example
To try the bundled example app (which enables WebMCP via
webmcp=True):(To enable automatic WebMCP tools on any existing Shiny app without code changes, start it with
SHINY_WEBMCP=1 shiny run app.py)2. Interact with the app alongside an agent
Open the app in a browser that supports WebMCP (e.g., Chrome with WebMCP enabled). Both you and the browser agent share the open dashboard.
Ask your browser agent:
Here is what happens step-by-step:
compare_channels(region="West")to calculate sales on the server without changing the user's dashboard view, returning:{"region": "West", "currency": "USD", "Online": 600, "Retail": 300, "online_minus_retail": 300}shiny_set_inputs(values={"region": "West", "channel": "Online"}).3. How to add a custom tool to your own app
Adding a tool for an agent to use in your server function is simple:
The README and bundled Shiny agent reference explain setup, supported controls, custom tools, and limits.
SkillDiff: Evaluate WebMCP v/s Playwright
Ran SkillDiff with GPT-6 Sol, using this task:
Both agents returned $600 online, $300 retail, +$300 difference and left the correct filters selected.
When running with
GPT-6 Lunawe got this table