Skip to contents

shinymcp is strongest when an AI assistant needs to do more than print a number. The assistant can call a tool, receive structured data for reasoning, and show the user an interactive card with controls, tables, plots, and formatted output. The card also reports the user’s interactions back into the model’s context, so the assistant can act on what the user did in its next turn.

The examples in order

The bundled examples are ordered so each one adds a single new idea. Work through them in order and you’ll have touched every major feature of the package. Each lives at system.file("examples", "<name>", "app.R", package = "shinymcp"), and each runs in preview_app() (a local reference host with a protocol log) or as a stdio MCP server via Rscript app.R.

Level Example What it adds
1 hello-mcp-minimal The whole contract: one input, one tool, one output, ~30 lines
2 bslib-inputs Native shiny/bslib inputs auto-detected by id, no wrappers
3 penguins A real dashboard: ggplot2, multiple outputs, a declared outputSchema
4 feature-tour The protocol features: app-only tools, lazy resources, theme syncing, window.shinymcp
5 multi-tool One app, several tools, where connected reactive groups become separate contracts
6 use-cases gallery Realistic chat cards with typed model_value handoffs (this article)
7 shinychat-card + rpharma-hangout Embedding: the same McpApp inside Shiny dashboards and shinychat

Every level builds on the same three ideas. Names are the contract: tool argument names match input ids, and result keys match output ids. That is the only binding mechanism. One result serves two consumers, so the human gets the rendered card and the model gets structured values it can reason over instead of scraping the display. And one definition runs in several places: the same McpApp serves to Claude over MCP, embeds in a Shiny app, and wraps as a shinychat tool card.

Level 4 in detail: the feature tour

feature-tour packs the MCP Apps protocol features into one annotated app. Open it in preview_app() with the protocol log visible and you can watch each one on the wire:

source(system.file("examples", "feature-tour", "app.R", package = "shinymcp"))

What to look for:

  • App-only tools (tool_visibility): the fetch_region_detail tool is callable from the card’s “Load region detail” button but carries _meta.ui.visibility = ["app"], so the model never sees it. Use this to keep UI plumbing, or human-only detail views, out of the model’s tool list.
  • Lazy resources (resources plus window.shinymcp.readResource()): the region catalog isn’t inlined into the HTML. The card fetches it through the host at startup. This is how you ship large datasets without bloating the ui:// resource.
  • Declared result shapes (tool_outputs): the analysis tool publishes an outputSchema, so hosts and models know it returns a base64 plot named trend and a text summary named summary before ever calling it.
  • Theme syncing: flip your OS or host theme and the card follows. The bridge maps the host’s theme onto Bootstrap’s data-bs-theme.
  • Host interactions (window.shinymcp): buttons that send a message into the conversation, open a link, and request fullscreen. These are spec methods, so a host that doesn’t support one rejects the call.

The gallery contains three small but realistic MCP Apps:

Use case What it demonstrates
Revenue scenario board Scenario controls, model-facing structured values, a table, and an ARR plot
Experiment planner Statistical planning, a power curve, and a concise recommendation
Incident triage console Operational decision support, status HTML, and a runbook table

The apps are intentionally card-sized: controls fit in a compact grid, the primary answer is immediately visible, and secondary tables stay available without taking over the chat transcript. Each declares tool_outputs (so its result shape is part of the published contract) and prefers_border (a rendering hint for the host).

Run a use case as an MCP App

The gallery entrypoint serves one use case at a time. Set SHINYMCP_USE_CASE to revenue, experiment, or incident.

SHINYMCP_USE_CASE=revenue Rscript \
  "$(Rscript -e 'cat(system.file("examples", "use-cases", "app.R", package = "shinymcp"))')"

For Claude Desktop or another MCP host, point the server command at that same app.R file and set the environment variable for the use case you want to show.

Revenue scenario board

This card turns go-to-market assumptions into a twelve-month forecast. The assistant can reason over the structured result while the user sees the ARR trajectory and monthly forecast table.

source(system.file("examples", "use-cases", "apps.R", package = "shinymcp"))
app <- shinymcp_use_case("revenue")
app$call_tool("forecast_revenue", list(
  segment = "Mid-market",
  visitors = 25000,
  trial_rate = 7,
  win_rate = 22,
  contract_value = 9000,
  monthly_churn = 2.5
))

Experiment planner

This card helps an assistant move from “can we detect a 15% lift?” to a specific sample size and runtime. The plot gives the human reviewer a quick sense of how much margin the design has.

source(system.file("examples", "use-cases", "apps.R", package = "shinymcp"))
app <- shinymcp_use_case("experiment")
app$call_tool("plan_experiment", list(
  baseline_rate = 12,
  minimum_effect = 15,
  target_power = 0.9,
  traffic_per_day = 6000
))

Incident triage console

This card is useful for support, SRE, and operations chats. The assistant can collect facts conversationally, call the tool, and return a priority, briefing, and runbook without losing the structured values it needs for follow-up.

source(system.file("examples", "use-cases", "apps.R", package = "shinymcp"))
app <- shinymcp_use_case("incident")
app$call_tool("triage_incident", list(
  service = "Payments",
  severity = "Degraded",
  affected_users = 1200,
  minutes_open = 24,
  regulated_data = TRUE
))

shinychat integration

The gallery also includes a Shiny app that registers all three cards as shinychat tool results through as_shinychat_tool().

Rscript "$(Rscript -e 'cat(system.file("examples", "use-cases", "shinychat-app.R", package = "shinymcp"))')"

When OPENAI_API_KEY is available, that app uses chat_mod_ui() and chat_mod_server() with one ellmer client per Shiny session. Without a configured model provider, it falls back to local demo mode: type revenue, experiment, or incident and the app appends a live shinymcp card directly.

The Shiny session is still the runtime for those cards: it registers the McpApp, receives bridge events from the iframe, and executes tool calls in R. The iframe itself remains a portable MCP App surface instead of a nested Shiny app, which keeps each chat card small and reusable outside Shiny.

For the full embedding-and-governance story (contract inspectors, typed meeting-note handoffs, approved skill registries), see the R/Pharma demo at system.file("examples", "rpharma-hangout", package = "shinymcp").

What the examples cover

These examples cover the surfaces most teams need before adopting MCP Apps:

  • Rich UI for people: inputs, tables, plots, and formatted HTML.
  • Structured values for the model: the assistant can reason over numbers without scraping the display, and ui/update-model-context keeps it aware of what the user changed in the card.
  • Declared contracts: input schemas, output schemas, visibility scoping, and resource metadata that a reviewer can inspect before anything runs.
  • Portable deployment: the same McpApp can be served to an MCP host, embedded in Shiny, or wrapped as a shinychat tool card. In hosts without MCP Apps support, the same tools run as plain text tools.
  • Small cards over giant dashboards: each card has one job and maps cleanly to one tool call.