Module: McpToolkit::Transport::ControllerMethods

Extended by:
ActiveSupport::Concern
Included in:
ServerController
Defined in:
lib/mcp_toolkit/transport/controller_methods.rb

Overview

The MCP Streamable-HTTP transport, provided as an includable concern. An app's controller includes this to get the full transport with no per-app code:

class Mcp::ServerController < ApplicationController
include McpToolkit::Transport::ControllerMethods
end

and routes the four endpoints at its actions:

post   "mcp",        to: "mcp/server#create"
get    "mcp",        to: "mcp/server#stream"
delete "mcp",        to: "mcp/server#destroy"
get    "mcp/health", to: "mcp/server#health"

Endpoints POST /mcp - JSON-RPC requests/responses GET /mcp - server-initiated SSE stream (none emitted; 405) DELETE /mcp - terminate the current session GET /mcp/health - unauthenticated health probe

Authentication The bearer token is NOT verified at the transport boundary; it is forwarded into each tool, which authenticates it against the central app's introspection endpoint (McpToolkit::Auth::Authenticator). The transport only requires that a token be present (so unauthenticated calls are refused before any work). Tools resolve the active account from _meta / account_id argument / the account-id header.

Session lifecycle

  • First initialize POST: create a session, return its id in the Mcp-Session-Id response header. The client echoes it on later requests.
  • Subsequent POSTs: validate the session id; missing/expired => 404.
  • DELETE /mcp ends the session.

Notifications (requests without an id) get a 202 with no body.

Overridable hooks

  • mcp_config -> the McpToolkit::Configuration to use (default: McpToolkit.config)
  • mcp_extra_tools -> Array of additional MCP::Tool subclasses (default: [])

CSRF: the concern disables forgery protection (this is a token-authenticated JSON API). Inherit from ActionController::Base (not ::API) if your app's controller stack needs helper_method, as bsa-notifications does.

Constant Summary collapse

SESSION_HEADER =
"Mcp-Session-Id"

Instance Method Summary collapse

Instance Method Details

#createObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mcp_toolkit/transport/controller_methods.rb', line 60

def create
  request_body = mcp_parsed_body
  server = McpToolkit::Server.build(
    server_context: mcp_server_context,
    config: mcp_config,
    extra_tools: mcp_extra_tools
  )
  response_json = server.handle_json(JSON.generate(request_body))

  # handle_json returns nil for notifications (no id) -> 202 Accepted, no body.
  return head :accepted if response_json.nil?

  mcp_render_response(response_json)
end

#destroyObject

DELETE /mcp - terminate the current session.



81
82
83
84
# File 'lib/mcp_toolkit/transport/controller_methods.rb', line 81

def destroy
  McpToolkit::Session.delete(request.headers[SESSION_HEADER], config: mcp_config)
  head :no_content
end

#healthObject

GET /mcp/health - unauthenticated probe.



87
88
89
90
91
92
93
# File 'lib/mcp_toolkit/transport/controller_methods.rb', line 87

def health
  render json: {
    status: "ok",
    server: mcp_config.server_name,
    version: mcp_config.server_version
  }
end

#streamObject

GET /mcp - no server-initiated SSE stream is emitted; 405 per MCP spec.



76
77
78
# File 'lib/mcp_toolkit/transport/controller_methods.rb', line 76

def stream
  head :method_not_allowed
end