annotation ActionController::MCP
#
configures how a route, or every route in a controller, is exposed by the
optional MCP server (see ActionController::MCPServer)
hide: trueexcludes the route(s) from the MCP toolboxesroot: truealways lists the tool(s) or prompt(s), without opening the toolboxendpoint: true(controllers only) also serves the controller as its own MCP server at<base>/mcp, or at a sub path such asendpoint: "/assistant". Path params in the base (base "/accounts/:account_id") are bound from the endpoint URL. The controller is hidden from the global server unless it's annotatedhide: false, and a method annotatedhide: trueis hidden from bothui: "bookings/card.html"renders the HTML card at that path, inMCPServer.ui_base, for the tool's results in clients that support MCP Apps (ui://bookings/card.html)visibility: :cardmakes the tool callable by cards only, it's hidden from the model.visibility: :modelstops cards calling it, the default is[:model, :card]behaviour:describes what the tool does, a symbol or an array of:read_only,:additive,:destructive,:idempotent,:open_worldand:closed_world. It replaces the defaults inferred from the HTTP verb: GET is:read_only, PUT is:idempotentand DELETE is[:destructive, :idempotent]. Read only tools can be run with thecall_read_onlyproxytitle: "Book a room"is the tool or prompt's display nameresource: "app://widgets/{id}"(GET routes) also exposes the route as an MCP resource template. The variables are the route's path params, and{?name,other}its query params.mime_type:is the type of the resource contents,cache_ttl:(seconds) the time clients may cache a read andsubscribe: truelets clients subscribe to updates, which requires a watcher, seeMCPServer.watchlong_running: truestreams progress to MCP clients while the route runs, seeMCPServer::RequestContext, and spools its response to a temporary file rather than memory.max_bytes:limits the response size
tools with ui: or visibility: :card are root: true unless annotated root: false,
as hosts only render cards for, and let cards call, the tools in their tool list.
Icons are added with @[AC::Icon]
* prompt: true exposes a method as an MCP prompt (not as a HTTP route).
The method must return String or Array(AC::PromptMessage)
a method level annotation overrides the controller level annotation The nearest annotated controller supplies defaults for inherited and newly declared actions; a child controller annotation replaces those defaults.
@[AC::MCP(hide: true)]
class Internal < AC::Base
# exposed even though the rest of the controller is hidden
@[AC::MCP(hide: false)]
@[AC::Route::GET("/status")]
def status : String
"ok"
end
end
class Widgets < AC::Base
# summarise a widget for the user
@[AC::MCP(prompt: true)]
def summarise(
@[AC::Param::Info(description: "the widget to summarise")]
id : Int64,
) : String
"Summarise the widget: #{Widget.find(id).to_json}"
end
end