shinyprobe
# shinyprobe
An MCP server that gives coding agents hands and eyes on a running Shiny app, R or Python.
## Why
Coding agents write Shiny code blind. Once the app runs, they cannot set an input, see the
plot, or tell which output broke and why. shinyprobe gives them a real browser on the running
app, and it understands Shiny rather than just the page.
**It knows when Shiny has finished.** Every action waits for the app to settle, then reports
which outputs changed and what went wrong. No sleeping, polling or guessing from screenshots.
A generic browser tool cannot tell "still computing" from "nothing happened"; shinyprobe can,
including on slow hosted apps.
**Errors come with an address.** A failing output returns the R or Python traceback, with
file and line (`app.R#14`), attached to the output it broke. `validate()` is a warning,
`req()` is silent, and only real errors are errors. A crash says so, with the exit code and
the last console lines.
**It catches mistakes you would not see.** It warns when a widget rejects a value (a select
given a choice it doesn't have) and when an output never renders, usually a typo'd id. Both
otherwise look fine and are quietly wrong.
**It handles real app structure.** Tabs, accordions, sidebars, `renderUI` and modules all
work. Clicking something on another tab opens that tab first, as a user would. If a
`conditionalPanel` hides it, the error names the condition to meet.
**It shortens the fix-and-check loop.** `get_console` shows what the app printed.
`launch_app(replay=True)` restarts the app after a code change and replays the same inputs
and clicks, so "fix it, then get back to where it broke" is one call.
**It returns data, not just pictures.** Tables come back as columns and rows, plots with
their axis ranges and mapped variables, htmlwidgets with their data payload.
**It stays out of your app.** No R packages to install, no changes to your code. It works on
local apps and on public deployments.
The difference: an agent can *check* its work instead of assuming it. "I've written the
change" becomes "I've written the change, set `n` to 5, the table has five rows, and nothing
errored".
## Quickstart
uvx shinyprobe install-browser
claude mcp add shinyprobe -- uvx shinyprobe
Then ask your agent to launch your app, change inputs and read outputs.
You need R with `shiny` for R apps, or a Python with `shiny` for Python apps. shinyprobe finds
`Rscript` and `python` on your PATH (and R's default install folder on Windows); set
`SHINYPROBE_RSCRIPT` or `SHINYPROBE_PYTHON` to use others. Set `SHINYPROBE_HEADED=1` to
watch the browser.
## Tools
| Tool | What it does |
|---|---|
| `launch_app` | Start the app in a folder or file and open it. Relaunching the same path keeps the `app_id`; `replay=True` reruns the previous run's actions. |
| `attach` | Open an app that is already running, locally or deployed. |
| `stop_app` | Close the page and stop a launched app. |
| `list_controls` | Every input (id, type, label, value, choices) and output (id, type, status), with visibility. |
| `set_inputs` | Set inputs through their widgets and wait for the app to settle. |
| `click` | Click a button, opening any tab or panel around it first. |
| `show` | Open the tab, accordion panel, sidebar or `<details>` holding an element, by id or label. |
| `upload_file` | Upload a local file into a file input. |
| `read_outputs` | Text, tables as rows, plots and widgets as images plus their data. |
| `get_errors` | Every error so far: server traces, output errors, browser errors, crashes. |
| `get_console` | The app's own console output, for launched apps. |
| `screenshot` | The whole page or one element. |
Every action returns the same envelope: `status` (`settled`, `no_change`, `timeout` or
`disconnected`), `changed_outputs`, `errors` and `warnings`.
## Hosted apps
`attach` works on public deployments such as shinyapps.io. You lose what lives in the host's
process: no server tracebacks, no console, and hosts usually hide error messages ("An error
has occurred…"), though you still learn which output failed. Each attach is a real session
on that server and counts towards its usage. Apps behind a login are not supported yet.
TDQS
Scored across 12 tools
Every tool targets a distinct action: lifecycle (attach, launch_app, stop_app), UI inspection (list_controls), interaction (set_inputs, click, show, upload_file), output reading (read_outputs), and diagnostics (get_errors, screenshot, get_console). No two tools overlap in purpose, making misselection highly unlikely.
All names follow a consistent verb_noun pattern in snake_case (e.g., launch_app, set_inputs, read_outputs). Single verbs like attach and click are still clear and fit the pattern, with no mixed conventions or vague terms.
12 tools is well-scoped for a Shiny app interaction server. Each tool covers a necessary capability for starting, controlling, inspecting, and debugging apps, without redundancy or bloat.
The surface covers the full lifecycle from launch to stop, all common input interactions, output reading, and error/console diagnostics. No obvious gaps exist for typical Shiny testing workflows, making the set self-sufficient.