Skip to content

module ActionController::MCPServer #

Exposes the application's annotated routes as an MCP server using the Streamable HTTP transport.

Controllers are presented as toolboxes and their routes as tools. To keep the model's context lean only three tools are listed by default:

  • list_toolboxes lists the controllers and their descriptions
  • open_toolbox(name) adds the controller's routes to the session's tool set
  • close_toolbox(name) removes them again

Tool calls are dispatched in-process through the application router, so filters, authentication and error handlers apply exactly as they would for a regular request.

require "action-controller/mcp"

server = ActionController::Server.new
ActionController::MCPServer.mount(server, "/mcp")
server.run

Tool descriptions are extracted from the source code comments, so they need to be generated at build time and shipped alongside the binary:

ActionController::MCPServer.write_description("mcp.yml")

the file is lazily loaded from description_path the first time it is needed. Routes can be excluded using @[AC::MCP(hide: true)]

Extended modules

ActionController::MCPServer

Constants#

DEFAULT_INSTRUCTIONS = "Tools are grouped into toolboxes. Call list_toolboxes to discover what is available,\nopen_toolbox to load the tools in a toolbox and close_toolbox once you no longer need them."#

PROTOCOL_VERSIONS = {"2025-11-25", "2025-06-18", "2025-03-26"}#

supported protocol versions, newest first

Class methods#

.allowed_origins : Array(String)#

browser origins permitted to connect, in addition to same origin requests. "*" permits any origin

View source

.allowed_origins=(allowed_origins : Array(String))#

browser origins permitted to connect, in addition to same origin requests. "*" permits any origin

View source

.auth_cache_ttl : Time::Span#

how long a successful authentication check is cached for

View source

.auth_cache_ttl=(auth_cache_ttl : Time::Span)#

how long a successful authentication check is cached for

View source

.auth_probe : String | ::Nil#

a route used to authenticate MCP requests, i.e. /api/v1/users/current.

the route is requested in-process with the forwarded headers, a successful (2xx) response indicates the request is authenticated

View source

.auth_probe=(auth_probe : String | Nil)#

a route used to authenticate MCP requests, i.e. /api/v1/users/current.

the route is requested in-process with the forwarded headers, a successful (2xx) response indicates the request is authenticated

View source

.authenticator : Proc(HTTP::Request, Bool) | ::Nil#

authenticates MCP requests, returning true if the request is permitted.

optional, see auth_probe for a simpler alternative

View source

.authenticator=(authenticator : Proc(HTTP::Request, Bool) | Nil)#

authenticates MCP requests, returning true if the request is permitted.

optional, see auth_probe for a simpler alternative

View source

.description_path : String#

location of the MCP description file, generated using write_description

View source

.description_path=(description_path : String)#

location of the MCP description file, generated using write_description

View source

.forward_headers : Array(String)#

request headers copied from the MCP request to the route being invoked, typically used for authentication

View source

.forward_headers=(forward_headers : Array(String))#

request headers copied from the MCP request to the route being invoked, typically used for authentication

View source

.instructions : String | ::Nil#

usage instructions provided to the model

View source

.instructions=(instructions : String | Nil)#

usage instructions provided to the model

View source

.resource_metadata : Proc(HTTP::Request, ResourceMetadata) | ::Nil#

advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens. The request is provided for multi-tenant deployments

View source

.resource_metadata=(resource_metadata : Proc(HTTP::Request, ResourceMetadata) | Nil)#

advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens. The request is provided for multi-tenant deployments

View source

.server_name : String#

reported to clients during initialization

View source

.server_name=(server_name : String)#

reported to clients during initialization

View source

.server_version : String#

reported to clients during initialization

View source

.server_version=(server_version : String)#

reported to clients during initialization

View source

.session_timeout : Time::Span#

sessions inactive for this period are discarded

View source

.session_timeout=(session_timeout : Time::Span)#

sessions inactive for this period are discarded

View source

Methods#

#auth_enabled? : Bool#

authentication is optional and enabled when any of authenticator, auth_probe or resource_metadata is configured

View source

#description : Description#

the tool descriptions, lazily loaded from description_path.

if the file doesn't exist the description is generated from the compiled routes, however it will not include the documentation comments

View source

#description=(description : Description | Nil)#

replaces the current description, nil will reload it on next use

View source

#generate_description(docs : Bool = true) : Description#

generates the MCP description from the compiled routes.

docs: true extracts the source code comments using crystal docs, which requires access to the source code

View source

#mount(router : Router, path : String = "/mcp") : Transport#

mounts the MCP endpoint at the path provided.

tool calls are dispatched via the router, typically ActionController::Server. The OAuth protected resource metadata is served at /.well-known/oauth-protected-resource<path>

View source

#write_description(path : String = description_path) : Nil#

generates the description, including source code comments, and saves it to a file

View source