Wraps a standard Shiny module (UI function + server function) as an
McpApp. The module UI is rendered with MCP-compatible attributes, and
a tool definition is created that maps to the module's inputs and outputs.
If a handler is provided, the tool is fully functional; otherwise, a stub
handler is generated as a placeholder.
Usage
mcp_tool_module(
module_ui,
module_server,
name,
description,
handler = NULL,
arguments = NULL,
version = "0.1.0",
...
)Arguments
- module_ui
A Shiny module UI function that accepts an
idargument (e.g.,function(id) { ns <- NS(id); tagList(...) }).- module_server
A Shiny module server function. Currently stored as metadata for future headless Shiny session support, which will allow the module server to execute reactively when tools are called.
- name
Tool/app name. Used in
ui://resource URIs.- description
Human-readable description of what the tool does.
- handler
Optional tool handler function. If provided, this function is called when the MCP tool is invoked. Its arguments should match the module's input IDs. If
NULL, a stub handler is generated.- arguments
Optional list of
ellmer::type_string(),ellmer::type_number(), etc. for the tool's input schema. IfNULL, arguments are auto-detected from the rendered module UI.- version
App version string.
- ...
Additional arguments stored as module metadata (e.g., shared reactive values to pass to the module server when headless support lands).
Value
An McpApp object.
Details
This mirrors shinychat::chat_tool_module() for the MCP runtime — the
same module can be used in both contexts.
Examples
if (FALSE) { # \dontrun{
library(shiny)
# Define a standard Shiny module
hist_ui <- function(id) {
ns <- NS(id)
tagList(
sliderInput(ns("bins"), "Bins:", min = 5, max = 50, value = 25),
plotOutput(ns("plot"), height = "250px")
)
}
hist_server <- function(id, dataset) {
moduleServer(id, function(input, output, session) {
output$plot <- renderPlot({
hist(dataset(), breaks = input$bins, col = "#007bc2")
})
})
}
# Create and serve as MCP App
app <- mcp_tool_module(
hist_ui, hist_server,
name = "histogram",
description = "Show an interactive histogram",
handler = function(bins = 25) {
tmp <- tempfile(fileext = ".png")
grDevices::png(tmp, width = 600, height = 250)
hist(faithful$eruptions, breaks = bins, col = "#007bc2")
grDevices::dev.off()
list(plot = base64enc::base64encode(tmp))
}
)
serve(app)
} # }
