class ActionController::MCPServer::Protocol

Overview

implements the MCP methods. Requests are independent, there are no sessions, so the results only depend on the request and the path params bound from its URL

Defined in:

action-controller/mcp/protocol.cr

Constant Summary

CACHEABLE = {"server/discover", "tools/list", "prompts/list", "resources/list", "resources/templates/list", "resources/read"}

methods whose results clients can cache, 2026-07-28 onwards

META_TOOLS = {"{\"name\":\"list_toolboxes\",\"description\":\"Lists the available toolboxes, each groups related tools and prompts\",\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"annotations\":{\"readOnlyHint\":true}}", "{\"name\":\"open_toolbox\",\"description\":\"Returns the definitions of the tools in a toolbox and the names of its prompts\",\"inputSchema\":#{TOOLBOX_ARGS},\"annotations\":{\"readOnlyHint\":true,\"idempotentHint\":true}}"}
PROXY_ARGS = "{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\",\"description\":\"the tool name, as returned by open_toolbox\"},\"arguments\":{\"type\":\"object\",\"description\":\"the tool arguments, matching its inputSchema\"}},\"required\":[\"name\"]}"
PROXY_TOOLS = {"{\"name\":\"call_read_only\",\"description\":\"Runs a tool that only reads data (proxy: call_read_only) from a toolbox, as returned by open_toolbox\",\"inputSchema\":#{PROXY_ARGS},\"annotations\":{\"readOnlyHint\":true,\"openWorldHint\":false}}", "{\"name\":\"call_tool\",\"description\":\"Runs a tool that can change data (proxy: call_tool) from a toolbox, as returned by open_toolbox. Prefer call_read_only for tools that only read data\",\"inputSchema\":#{PROXY_ARGS},\"annotations\":{\"readOnlyHint\":false,\"openWorldHint\":false}}"}
TOOLBOX_ARGS = "{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\",\"description\":\"the toolbox name, as returned by list_toolboxes\"}},\"required\":[\"name\"]}"

Constructors

Instance Method Summary

Constructor Detail

def self.new(invoker : Invoker, endpoint : String | Nil = nil, composition : Composition = Composition.default) #

endpoint is the path template of a controller endpoint, nil for the global server


[View source]

Instance Method Detail

def cache_ttl(method : String, params : Hash(String, JSON::Any)) : Time::Span #

how long the result can be cached, resource templates can set their own


[View source]
def discover_result(request : HTTP::Request | Nil = nil, bound : Hash(String, String) = {} of String => String) : String #

the server/discover result, the server info is in the result's _meta


[View source]
def flat? : Bool #

a controller endpoint lists every tool directly, there are no toolboxes


[View source]
def handle(method : String, params : Hash(String, JSON::Any), request : HTTP::Request, bound : Hash(String, String), modern : Bool = false) : String #

returns the JSON result of the request. modern requests use 2026-07-28 or later


[View source]
def handle_streamed(method : String, params : Hash(String, JSON::Any), request : HTTP::Request, bound : Hash(String, String), modern : Bool = false) : String | StreamedResult #

returns the JSON result of the request, or a StreamedResult for long running routes, which the caller must close


[View source]
def initialize_result(protocol_version : String, request : HTTP::Request | Nil = nil, bound : Hash(String, String) = {} of String => String) : String #

the initialize result for the negotiated protocol version, before 2026-07-28

an endpoint's instructions method is run with the bound path params, raising RPCError or Unauthorized if it fails


[View source]
def long_running?(method : String, params : Hash(String, JSON::Any)) : Bool #

true if the request runs a long running route, which is streamed


[View source]
def server_info(json : JSON::Builder, request : HTTP::Request | Nil = nil) : Nil #

the server's Implementation, its name, version and icons


[View source]
def subscribable?(uri : String) : Tuple(Tool, Hash(String, String)) | Nil #

the subscribable resource tool matching the URI, and its template variables


[View source]