module
ActionController::MCPServer
Overview
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_toolboxeslists the controllers and their descriptionsopen_toolbox(name)adds the controller's routes to the session's tool setclose_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
Defined in:
action-controller/mcp.craction-controller/mcp/auth.cr
action-controller/mcp/description.cr
action-controller/mcp/invoker.cr
action-controller/mcp/protocol.cr
action-controller/mcp/session.cr
action-controller/mcp/transport.cr
Constant Summary
-
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
-
PROXY_INSTRUCTIONS =
"#{DEFAULT_INSTRUCTIONS}\nopen_toolbox returns the definitions of the tools it loads. If they don't appear in your\navailable tools, run them with the tool named in their proxy field, passing the tool name\nand its arguments: call_read_only for tools that only read data, call_tool for the rest."
Class Method Summary
-
.allowed_origins : Array(String)
browser origins permitted to connect, in addition to same origin requests.
-
.allowed_origins=(allowed_origins : Array(String))
browser origins permitted to connect, in addition to same origin requests.
-
.auth_cache_ttl : Time::Span
how long a successful authentication check is cached for
-
.auth_cache_ttl=(auth_cache_ttl : Time::Span)
how long a successful authentication check is cached for
-
.auth_probe : String | Nil
a route used to authenticate MCP requests, i.e.
-
.auth_probe=(auth_probe : String | Nil)
a route used to authenticate MCP requests, i.e.
-
.authenticator : Proc(HTTP::Request, Bool) | Nil
authenticates MCP requests, returning
trueif the request is permitted. -
.authenticator=(authenticator : Proc(HTTP::Request, Bool) | Nil)
authenticates MCP requests, returning
trueif the request is permitted. -
.description_path : String
location of the MCP description file, generated using
#write_description -
.description_path=(description_path : String)
location of the MCP description file, generated using
#write_description -
.excluded_response_headers : Array(String)
response headers left out of tool results, matched case-insensitively.
-
.excluded_response_headers=(excluded_response_headers : Array(String))
response headers left out of tool results, matched case-insensitively.
-
.forward_headers : Array(String)
request headers copied from the MCP request to the route being invoked, typically used for authentication
-
.forward_headers=(forward_headers : Array(String))
request headers copied from the MCP request to the route being invoked, typically used for authentication
- .instructions : String
-
.instructions=(instructions : String | Nil)
usage instructions provided to the model,
niluses.toolbox_instructionsand an empty string provides none. -
.resource_metadata : Proc(HTTP::Request, ResourceMetadata) | Nil
advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens.
-
.resource_metadata=(resource_metadata : Proc(HTTP::Request, ResourceMetadata) | Nil)
advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens.
-
.server_name : String
reported to clients during initialization
-
.server_name=(server_name : String)
reported to clients during initialization
-
.server_version : String
reported to clients during initialization
-
.server_version=(server_version : String)
reported to clients during initialization
-
.session_timeout : Time::Span
sessions inactive for this period are discarded
-
.session_timeout=(session_timeout : Time::Span)
sessions inactive for this period are discarded
-
.tool_proxy=(tool_proxy : Bool)
adds a
call_toolmeta tool that runs the tools in open toolboxes, for clients that don't refresh their tools when notified withtools/list_changed -
.tool_proxy? : Bool
adds a
call_toolmeta tool that runs the tools in open toolboxes, for clients that don't refresh their tools when notified withtools/list_changed -
.toolbox_instructions : String
explains how to use toolboxes, taking
tool_proxyinto account
Instance Method Summary
-
#auth_enabled? : Bool
authentication is optional and enabled when any of
.authenticator,.auth_probeor.resource_metadatais configured -
#description : Description
the tool descriptions, lazily loaded from
.description_path. -
#description=(description : Description | Nil)
replaces the current description,
nilwill reload it on next use -
#endpoint_paths : Array(String)
the path templates of the controller endpoints,
@[AC::MCP(endpoint: true)] -
#generate_description(docs : Bool = true) : Description
generates the MCP description from the compiled routes.
-
#mount(router : Router, path : String = "/mcp", endpoints : Bool = true) : Transport
mounts the MCP endpoint at the path provided.
-
#mount_endpoints(router : Router) : Array(Transport)
mounts a server for each controller annotated
@[AC::MCP(endpoint: true)] -
#write_description(path : String = description_path) : Nil
generates the description, including source code comments, and saves it to a file
Class Method Detail
browser origins permitted to connect, in addition to same origin requests.
"*" permits any origin
browser origins permitted to connect, in addition to same origin requests.
"*" permits any origin
how long a successful authentication check is cached for
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
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
authenticates MCP requests, returning true if the request is permitted.
optional, see .auth_probe for a simpler alternative
authenticates MCP requests, returning true if the request is permitted.
optional, see .auth_probe for a simpler alternative
location of the MCP description file, generated using #write_description
location of the MCP description file, generated using #write_description
response headers left out of tool results, matched case-insensitively. An entry
ending in * matches by prefix. Everything else (Link, X-Total-Count,
Content-Range, Location, ETag, ...) is returned to the model
response headers left out of tool results, matched case-insensitively. An entry
ending in * matches by prefix. Everything else (Link, X-Total-Count,
Content-Range, Location, ETag, ...) is returned to the model
request headers copied from the MCP request to the route being invoked, typically used for authentication
request headers copied from the MCP request to the route being invoked, typically used for authentication
usage instructions provided to the model, nil uses .toolbox_instructions and an
empty string provides none. Include .toolbox_instructions when describing your domain
advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens. The request is provided for multi-tenant deployments
advertises the OAuth authorization server so MCP clients can obtain and refresh access tokens. The request is provided for multi-tenant deployments
sessions inactive for this period are discarded
adds a call_tool meta tool that runs the tools in open toolboxes, for clients
that don't refresh their tools when notified with tools/list_changed
adds a call_tool meta tool that runs the tools in open toolboxes, for clients
that don't refresh their tools when notified with tools/list_changed
explains how to use toolboxes, taking tool_proxy into account
Instance Method Detail
authentication is optional and enabled when any of .authenticator,
.auth_probe or .resource_metadata is configured
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
replaces the current description, nil will reload it on next use
the path templates of the controller endpoints, @[AC::MCP(endpoint: true)]
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
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>
endpoints: true also mounts the controller endpoints, @[AC::MCP(endpoint: true)],
see #mount_endpoints
mounts a server for each controller annotated @[AC::MCP(endpoint: true)]
generates the description, including source code comments, and saves it to a file